writer.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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. {* TAbstractWriter *}
  13. {****************************************************************************}
  14. { $define serdebug}
  15. Procedure TAbstractWriter.AddAncestor(Component: TComponent);
  16. begin
  17. FAncestorList.Add(Component);
  18. end;
  19. Procedure TAbstractWriter.WriteData(Instance: TComponent);
  20. begin
  21. {$ifdef serdebug}
  22. Writeln(stderr,'Writer: Starting WriteData');
  23. {$endif}
  24. With Instance do
  25. StartObject(ClassName,Name);
  26. WriteProperties(Instance);
  27. Instance.GetChildren(@WriteComponent,FRoot);
  28. EndObject;
  29. end;
  30. {
  31. These methods do the main work: decide if a property must be written,
  32. and then call the write method.
  33. Later on the NeedsWriting function should take the ancestor into
  34. account as well, for form inheritance...
  35. }
  36. Procedure TAbstractWriter.DoOrdinalProp(Instance : TPersistent;Propinfo :PPropInfo);
  37. Var
  38. Value : longint;
  39. begin
  40. {$ifdef serdebug}
  41. Writeln(stderr,'Writer: Starting DoOrdinalProp');
  42. {$endif}
  43. Value:=GetOrdProp(Instance,Propinfo);
  44. If Value<>(PropInfo^.default) then
  45. With PropInfo^ do
  46. Case PropType^.Kind of
  47. tkInteger : WriteIntegerProperty(Name,Value);
  48. tkSet : WriteSetProperty (Name,Value,GetTypeData(Proptype)^.CompType^);
  49. tkEnumeration : WriteEnumerationProperty (Name,Value,GetEnumName(Proptype,Value));
  50. end;
  51. end;
  52. Procedure TAbstractWriter.DoStringProp(Instance : TPersistent;Propinfo :PPropInfo);
  53. Var Value : String;
  54. begin
  55. {$ifdef serdebug}
  56. Writeln(stderr,'Writer: Starting DoStringProp');
  57. {$endif}
  58. Value:=GetStrProp(Instance,PropInfo);
  59. If Value<>'' Then
  60. With Propinfo^ do
  61. WriteStringProperty(Name,Value);
  62. end;
  63. Procedure TAbstractWriter.DoFloatProp(Instance : TPersistent;Propinfo :PPropInfo);
  64. Var Value : Extended;
  65. begin
  66. {$ifdef serdebug}
  67. Writeln(stderr,'Writer: Starting DoFloatProp');
  68. {$endif}
  69. Value:=GetFloatProp(Instance,Propinfo);
  70. If (Value<>0.0) then
  71. With PropInfo^ do
  72. WriteFloatProperty(Name,Value);
  73. end;
  74. Procedure TAbstractWriter.DoCollectionProp(Name: ShortString; Value : TCollection);
  75. Var OldPrefix : String;
  76. begin
  77. {$ifdef serdebug}
  78. Writeln(stderr,'Writer: Starting DoCollectionProp');
  79. {$endif}
  80. Try
  81. OldPrefix:=FPrefix;
  82. FPrefix:='';
  83. WriteCollectionProperty(Name,Value)
  84. Finally
  85. FPrefix:=OldPrefix;
  86. end;
  87. end;
  88. Procedure TAbstractWriter.DoClassProp(Instance : TPersistent;Propinfo :PPropInfo);
  89. {
  90. Some explanation:
  91. 1) Only TPersistent properties can be written, since higher has no
  92. RTTI (actually, we could test if the class has RTTI if it isn't
  93. TPersistent, but Delphi doesn't - We can add it later)
  94. 2) If it is a TPersistent but not TComponent, then the only
  95. thing that is (can be) written is the defineproperties;
  96. we have this handled by calling writeproperties again.
  97. 3) When a property is a TComponent, it is owned by the form or by a
  98. TDataModule; This means that the component is streamed also
  99. (owner-owned) by the form, so it is sufficient to store a reference
  100. to the component, not store the component itself.
  101. Again, this is very form-oriented; at a later stage, we should see
  102. to make this more broader.
  103. }
  104. Var
  105. Value : TObject;
  106. Function NeedsWriting : Boolean;
  107. begin
  108. Result:=Value<>Nil;
  109. end;
  110. Function GetComponentPath(Component : TComponent): String;
  111. begin
  112. If Component.Owner=Root Then
  113. Result:=Component.Name // 2 objects In the same form.
  114. else if Component=Root then
  115. Result:='Owner' // Component = Form.
  116. else if Component.Owner<>Nil then
  117. Result:=Format('%s.%s',[Component.Owner.name,Component.Name]) // Component on other e.g. Datamodule.
  118. else
  119. Result:=Format('%s.%s',[Component.Name+'owner']); // All other cases.
  120. end;
  121. Var
  122. OldPrefix,CName : String;
  123. begin
  124. {$ifdef serdebug}
  125. Writeln(stderr,'Writer: Starting DoClassProp');
  126. {$endif}
  127. Value:=TObject(GetOrdProp(Instance,PropInfo)); // get as pointer
  128. {$ifdef serdebug}
  129. If Value=Nil then
  130. Writeln(stderr,'Writer: value is nil');
  131. Writeln(stderr,'name ',propinfo^.Name);
  132. {$endif}
  133. If (Value=Nil) Then
  134. begin
  135. If Needswriting then
  136. With Propinfo^ do
  137. WriteNilProperty(Name)
  138. end
  139. else
  140. If Value is TPersistent then
  141. begin
  142. {$ifdef serdebug}
  143. Writeln(stderr,'Writer: value is tpersistent');
  144. {$endif}
  145. If Value is TComponent then
  146. { Component is written by itself,
  147. just write a reference }
  148. begin
  149. Cname:=GetComponentPath(TComponent(Value));
  150. If NeedsWriting and (Cname<>'') then
  151. begin
  152. With PropInfo^ do
  153. WriteComponentProperty(Name,TComponent(Value));
  154. end;
  155. end
  156. else If Value is TCollection then
  157. DoCollectionProp(Propinfo^.Name,TCollection(Value))
  158. else
  159. With Propinfo^ do
  160. begin // TPersistent, not TComponent.
  161. OldPrefix:=FPrefix;
  162. FPrefix:=Format('%s%s.',[OldPrefix,Name]); // eg. Memo.Lines.Strings !
  163. try
  164. WriteProperties(TPersistent(Value));
  165. finally
  166. FPrefix:=OldPrefix;
  167. end;
  168. end;
  169. end
  170. // We can't write it if it isn't a TPersistent...
  171. end;
  172. Procedure TAbstractWriter.DoMethodProp(Instance : TPersistent;Propinfo :PPropInfo);
  173. {
  174. Some explanation: AFAIK Delphi only allows to assign methods from the
  175. current form to an event. (An event is a Method) this means that the
  176. instance part of the method IS the Form which IS the 'root' component.
  177. this means that we can safely assume that Method.Data = Root...
  178. Remark also that Form Methods are always in a Published section of the form,
  179. Since Delphi manages them, hence the method name is always in RTTI.
  180. If we want a more general streaming method (i.e. not form oriented) then
  181. we would have to write ComponentPath.MethodName or something.
  182. }
  183. Var
  184. Value : TMethod;
  185. begin
  186. {$ifdef serdebug}
  187. Writeln(stderr,'Writer: Starting DoMethodProp');
  188. {$endif}
  189. Value:=GetMethodProp(Instance,Propinfo);
  190. With Value do
  191. If Code<>Nil then
  192. WriteMethodProperty(Propinfo^.Name,Root.MethodName(Code));
  193. end;
  194. Procedure TAbstractWriter.WriteProperty(Instance: TPersistent; PropInfo: Pointer);
  195. {$ifdef serdebug}
  196. Const
  197. TypeNames : Array [TTYpeKind] of string[15] =
  198. ('Unknown','Integer','Char','Enumeration',
  199. 'Float','Set','Method','ShortString','LongString',
  200. 'AnsiString','WideString','Variant','Array','Record',
  201. 'Interface','Class','Object','WideChar','Bool');
  202. Const OrdinalTypes = [tkInteger,tkChar,tkENumeration,tkbool];
  203. {$endif}
  204. begin
  205. {$ifdef serdebug}
  206. Writeln(stderr,'Writer: Starting WriteProperty');
  207. With PPropInfo(Propinfo)^ do
  208. begin
  209. Writeln (stderr,' Type kind: ',TypeNames[PropType^.Kind]);
  210. Writeln (stderr,' Type Name: ',PropType^.Name);
  211. Writeln (stderr,'Writer: Starting WriteProperty');
  212. end;
  213. {$endif}
  214. // Dispatching routine. For compatibility only.
  215. With PPropinfo(Propinfo)^ do
  216. Case PropType^.Kind of
  217. tkchar,tkInteger,tkenumeration,tkset : DoOrdinalProp(Instance,Propinfo);
  218. tkAstring,tkstring,tkLString,tkWstring : DoStringProp(Instance,Propinfo);
  219. tkfloat : DoFloatProp(Instance,PropInfo);
  220. tkClass : DoClassProp(Instance,PropInfo);
  221. tkMethod : DoMethodProp(Instance,PropInfo);
  222. end;
  223. end;
  224. Procedure TAbstractWriter.WriteProperties(Instance: TPersistent);
  225. Var I,PropCount : Longint;
  226. Props : PPropList;
  227. begin
  228. {$ifdef serdebug}
  229. Writeln(stderr,'Writer: Starting WriteProperties');
  230. {$endif}
  231. PropCount:=GetTypeData(Instance.ClassInfo)^.PropCount;
  232. {$ifdef serdebug}
  233. Writeln(stderr,'Writer : Propcount: ',PropCount);
  234. {$endif}
  235. Try
  236. GetMem (Props,SizeOf(Pointer)*PropCount);
  237. GetPropInfos(Instance.ClassInfo,Props);
  238. For I:=0 to PropCount-1 do
  239. WriteProperty(Instance,Props^[I]);
  240. finally
  241. FreeMem(Props);
  242. end;
  243. // Instance.DefineProperties(Self);
  244. end;
  245. Destructor TAbstractWriter.Destroy;
  246. begin
  247. end;
  248. Procedure TAbstractWriter.WriteDescendent(ARoot: TComponent; AAncestor: TComponent);
  249. begin
  250. {$ifdef serdebug}
  251. Writeln(stderr,'Writer: Starting WriteDescendent');
  252. {$endif}
  253. FRootAncestor:=AAncestor;
  254. FAncestor:=Ancestor;
  255. FRoot:=ARoot;
  256. WriteComponent(ARoot)
  257. end;
  258. Procedure TAbstractWriter.WriteRootComponent(ARoot: TComponent);
  259. begin
  260. {$ifdef serdebug}
  261. Writeln(stderr,'Writer: Starting WriteRootComponent');
  262. {$endif}
  263. WriteDescendent(ARoot,Nil);
  264. end;
  265. procedure TAbstractWriter.WriteComponent(Component: TComponent);
  266. Var I : longint;
  267. TheAncestor : TComponent;
  268. begin
  269. {$ifdef serdebug}
  270. Writeln(stderr,'Writer: Starting WriteComponent');
  271. {$endif}
  272. Include(Component.FComponentState,csWriting);
  273. TheAncestor:=Nil;
  274. If Assigned(FAncestorList) then
  275. For I:=0 to FAncestorList.Count-1 do
  276. If TComponent(FAncestorList[i]).Name=Component.Name then
  277. begin
  278. TheAncestor:=Tcomponent(FancestorList[i]);
  279. break;
  280. end;
  281. Ancestor:=TheAncestor;
  282. Component.WriteState(Self);
  283. Exclude(Component.FComponentState,csWriting);
  284. end;
  285. { ---------------------------------------------------------------------
  286. TWriter Methods
  287. ---------------------------------------------------------------------}
  288. Constructor TWriter.Create(S : TStream);
  289. begin
  290. FStream:=S;
  291. end;
  292. Destructor TWriter.Destroy;
  293. begin
  294. end;
  295. Procedure TWriter.FlushBuffer;
  296. begin
  297. // For compatibility only.
  298. end;
  299. Procedure TWriter.Write(const Buf; Count: Longint);
  300. begin
  301. FStream.Write(Buf,Count);
  302. end;
  303. Procedure TWriter.WriteIntegerProperty(Const Name : Shortstring;Value : Longint);
  304. begin
  305. WritePropName(Name);
  306. WriteInteger(Value);
  307. end;
  308. Procedure TWriter.WriteSetProperty (Const Name : ShortString;Value : longint; BaseType : TTypeInfo);
  309. begin
  310. WritePropName(Name);
  311. end;
  312. Procedure TWriter.WriteEnumerationProperty (Const Name : ShortString;Value : Longint; Const EnumName : ShortSTring);
  313. begin
  314. WritePropName(Name);
  315. WriteIdent(EnumName);
  316. end;
  317. Procedure TWriter.WriteStringProperty(Const Name : ShortString; Const Value : String);
  318. begin
  319. WritePropName(Name);
  320. WriteString(Value);
  321. end;
  322. Procedure TWriter.WriteFloatProperty(Const Name : ShortString; Value : Extended);
  323. begin
  324. WritePropName(Name);
  325. WriteFloat(Value);
  326. end;
  327. Procedure TWriter.WriteCollectionProperty(Const Name : ShortString;Value : TCollection);
  328. begin
  329. end;
  330. Procedure TWriter.WriteClassProperty(Instance : TPersistent;Propinfo :PPropInfo);
  331. begin
  332. end;
  333. Procedure TWriter.WriteComponentProperty(Const Name : ShortString; Value : TComponent);
  334. begin
  335. WritePropName(Name);
  336. WriteIdent(Value.Name);
  337. end;
  338. Procedure TWriter.WriteNilProperty(Const Name : Shortstring);
  339. begin
  340. WritePropName(Name);
  341. WriteValue(vaNil)
  342. end;
  343. Procedure TWriter.WriteMethodProperty(Const Name,AMethodName : Shortstring);
  344. begin
  345. end;
  346. procedure TWriter.WriteBoolean(Value: Boolean);
  347. begin
  348. If Value then WriteValue(vaTrue) else WriteValue(vaFalse)
  349. end;
  350. procedure TWriter.WriteCollection(Value: TCollection);
  351. begin
  352. end;
  353. procedure TWriter.WriteChar(Value: Char);
  354. begin
  355. end;
  356. procedure TWriter.WriteFloat(Value: Extended);
  357. begin
  358. end;
  359. procedure TWriter.WriteIdent(const Ident: string);
  360. begin
  361. if (Ident='Nil') then WriteValue(vaNil) else
  362. if (Ident='True') then WriteValue(vaTrue) else
  363. If (Ident='False') then WriteValue(vaFalse) else
  364. begin
  365. WriteValue(vaIdent);
  366. WriteStr(Ident);
  367. end
  368. end;
  369. procedure TWriter.WriteInteger(Value: Longint);
  370. begin
  371. If (Value>=-128) and (Value<=127) then
  372. begin
  373. WriteValue(vaInt8);
  374. Write(Value,SizeOf(ShortInt));
  375. end
  376. else If (Value>=-32768) and (Value<=32767) then
  377. begin
  378. WriteValue(vaInt16);
  379. Write(Value,SizeOf(SmallInt));
  380. end
  381. else
  382. begin
  383. WriteValue(vaInt32);
  384. Write(Value,SizeOf(Longint));
  385. end;
  386. end;
  387. procedure TWriter.WriteListBegin;
  388. begin
  389. WriteValue(vaList);
  390. end;
  391. procedure TWriter.WriteListEnd;
  392. begin
  393. WriteValue(vaNull)
  394. end;
  395. procedure TWriter.WriteSignature;
  396. begin
  397. Write(FilerSignature,SizeOf(FilerSignature));
  398. end;
  399. procedure TWriter.WriteStr(const Value: string);
  400. Var L : longint;
  401. begin
  402. L:=Length(Value);
  403. If L>255 then
  404. L:=255;
  405. Write(L,SizeOf(Byte));
  406. Write(Pointer(Value)^,L);
  407. end;
  408. procedure TWriter.WriteString(const Value: string);
  409. Var L : longint;
  410. begin
  411. L:=Length(Value);
  412. If L<=255 then
  413. begin
  414. WriteValue(vastring);
  415. Write(L,SizeOf(Byte));
  416. end
  417. else
  418. begin
  419. WriteValue(vaLstring);
  420. Write(L,SizeOf(Longint))
  421. end;
  422. Write(Pointer(Value)^,L);
  423. end;
  424. Procedure TWriter.WritePrefix(Flags: TFilerFlags; AChildPos: Integer);
  425. begin
  426. end;
  427. Procedure TWriter.WriteValue(Value : TValueType);
  428. begin
  429. Write(Value,SizeOf(Value));
  430. end;
  431. Procedure TWriter.WriteBuffer;
  432. begin
  433. // For compatibility only.
  434. end;
  435. function TWriter.GetPosition: Longint;
  436. begin
  437. GetPosition:=0;
  438. end;
  439. Procedure TWriter.SetPosition(Value: Longint);
  440. begin
  441. end;
  442. Procedure TWriter.WriteBinary(wd : TStreamProc);
  443. begin
  444. end;
  445. Procedure TWriter.WritePropName(const PropName: string);
  446. begin
  447. WriteStr(PropName)
  448. end;
  449. Procedure TWriter.DefineProperty(const Name: string;
  450. rd : TReaderProc; wd : TWriterProc;
  451. HasData: Boolean);
  452. begin
  453. end;
  454. Procedure TWriter.DefineBinaryProperty(const Name: string;
  455. rd, wd: TStreamProc;
  456. HasData: Boolean);
  457. begin
  458. end;
  459. Procedure TAbstractWriter.DefineProperty(const Name: string;
  460. rd : TReaderProc; wd : TWriterProc;
  461. HasData: Boolean);
  462. begin
  463. end;
  464. Procedure TAbstractWriter.DefineBinaryProperty(const Name: string;
  465. rd, wd: TStreamProc;
  466. HasData: Boolean);
  467. begin
  468. end;
  469. {
  470. $Log$
  471. Revision 1.6 2000-01-07 01:24:33 peter
  472. * updated copyright to 2000
  473. Revision 1.5 2000/01/06 01:20:33 peter
  474. * moved out of packages/ back to topdir
  475. Revision 1.2 2000/01/04 18:07:16 michael
  476. + Streaming implemented
  477. Revision 1.3 1999/09/13 08:35:16 fcl
  478. * Changed some argument names (Root->ARoot etc.) because the new compiler
  479. now performs more ambiguity checks (sg)
  480. Revision 1.2 1999/04/08 10:18:58 peter
  481. * makefile updates
  482. }