classes.inc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
  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. * Class implementations are in separate files. *
  13. **********************************************************************}
  14. var
  15. ClassList : TThreadlist;
  16. ClassAliasList : TStringList;
  17. {
  18. Include all message strings
  19. Add a language with IFDEF LANG_NAME
  20. just befor the final ELSE. This way English will always be the default.
  21. }
  22. {$IFDEF LANG_GERMAN}
  23. {$i constsg.inc}
  24. {$ELSE}
  25. {$IFDEF LANG_SPANISH}
  26. {$i constss.inc}
  27. {$ELSE}
  28. {$i constse.inc}
  29. {$ENDIF}
  30. {$ENDIF}
  31. { Utility routines }
  32. {$i util.inc}
  33. { TBits implementation }
  34. {$i bits.inc}
  35. { All streams implementations: }
  36. { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
  37. { TCustomMemoryStream TMemoryStream }
  38. {$i streams.inc}
  39. { TParser implementation}
  40. {$i parser.inc}
  41. { TCollection and TCollectionItem implementations }
  42. {$i collect.inc}
  43. { TList and TThreadList implementations }
  44. {$i lists.inc}
  45. { TStrings and TStringList implementations }
  46. {$i stringl.inc}
  47. {$ifndef VER1_0}
  48. { TThread implementation }
  49. {$i tthread.inc}
  50. {$endif}
  51. { TPersistent implementation }
  52. {$i persist.inc }
  53. { TComponent implementation }
  54. {$i compon.inc}
  55. { TBasicAction implementation }
  56. {$i action.inc}
  57. { TDataModule implementation }
  58. {$i dm.inc}
  59. { Class and component registration routines }
  60. {$I cregist.inc}
  61. { Interface related stuff }
  62. {$ifdef HASINTF}
  63. {$I intf.inc}
  64. {$endif HASINTF}
  65. {**********************************************************************
  66. * Miscellaneous procedures and functions *
  67. **********************************************************************}
  68. { Point and rectangle constructors }
  69. function Point(AX, AY: Integer): TPoint;
  70. begin
  71. with Result do
  72. begin
  73. X := AX;
  74. Y := AY;
  75. end;
  76. end;
  77. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  78. begin
  79. with Result do
  80. begin
  81. X := AX;
  82. Y := AY;
  83. end;
  84. end;
  85. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  86. begin
  87. with Result do
  88. begin
  89. Left := ALeft;
  90. Top := ATop;
  91. Right := ARight;
  92. Bottom := ABottom;
  93. end;
  94. end;
  95. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  96. begin
  97. with Result do
  98. begin
  99. Left := ALeft;
  100. Top := ATop;
  101. Right := ALeft + AWidth;
  102. Bottom := ATop + AHeight;
  103. end;
  104. end;
  105. { Object filing routines }
  106. var
  107. IntConstList: TThreadList;
  108. type
  109. TIntConst = class
  110. IntegerType: PTypeInfo; // The integer type RTTI pointer
  111. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  112. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  113. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  114. AIntToIdent: TIntToIdent);
  115. end;
  116. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  117. AIntToIdent: TIntToIdent);
  118. begin
  119. IntegerType := AIntegerType;
  120. IdentToIntFn := AIdentToInt;
  121. IntToIdentFn := AIntToIdent;
  122. end;
  123. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  124. IntToIdentFn: TIntToIdent);
  125. begin
  126. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  127. end;
  128. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  129. var
  130. i: Integer;
  131. begin
  132. with IntConstList.LockList do
  133. try
  134. for i := 0 to Count - 1 do
  135. if TIntConst(Items[i]).IntegerType = AIntegerType then
  136. exit(TIntConst(Items[i]).IntToIdentFn);
  137. Result := nil;
  138. finally
  139. IntConstList.UnlockList;
  140. end;
  141. end;
  142. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  143. var
  144. i: Integer;
  145. begin
  146. with IntConstList.LockList do
  147. try
  148. for i := 0 to Count - 1 do
  149. with TIntConst(Items[I]) do
  150. if TIntConst(Items[I]).IntegerType = AIntegerType then
  151. exit(IdentToIntFn);
  152. Result := nil;
  153. finally
  154. IntConstList.UnlockList;
  155. end;
  156. end;
  157. function IdentToInt(const Ident: String; var Int: LongInt;
  158. const Map: array of TIdentMapEntry): Boolean;
  159. var
  160. i: Integer;
  161. begin
  162. for i := Low(Map) to High(Map) do
  163. if CompareText(Map[i].Name, Ident) = 0 then
  164. begin
  165. Int := Map[i].Value;
  166. exit(True);
  167. end;
  168. Result := False;
  169. end;
  170. function IntToIdent(Int: LongInt; var Ident: String;
  171. const Map: array of TIdentMapEntry): Boolean;
  172. var
  173. i: Integer;
  174. begin
  175. for i := Low(Map) to High(Map) do
  176. if Map[i].Value = Int then
  177. begin
  178. Ident := Map[i].Name;
  179. exit(True);
  180. end;
  181. Result := False;
  182. end;
  183. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  184. var
  185. i : Integer;
  186. begin
  187. with IntConstList.LockList do
  188. try
  189. for i := 0 to Count - 1 do
  190. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  191. Exit(True);
  192. Result := false;
  193. finally
  194. IntConstList.UnlockList;
  195. end;
  196. end;
  197. { TPropFixup }
  198. type
  199. TPropFixup = class
  200. FInstance: TPersistent;
  201. FInstanceRoot: TComponent;
  202. FPropInfo: PPropInfo;
  203. FRootName: string;
  204. FName: string;
  205. constructor Create(AInstance: TPersistent; AInstanceRoot: TComponent;
  206. APropInfo: PPropInfo; const ARootName, AName: String);
  207. function MakeGlobalReference: Boolean;
  208. end;
  209. var
  210. GlobalFixupList: TThreadList;
  211. constructor TPropFixup.Create(AInstance: TPersistent; AInstanceRoot: TComponent;
  212. APropInfo: PPropInfo; const ARootName, AName: String);
  213. begin
  214. FInstance := AInstance;
  215. FInstanceRoot := AInstanceRoot;
  216. FPropInfo := APropInfo;
  217. FRootName := ARootName;
  218. FName := AName;
  219. end;
  220. function TPropFixup.MakeGlobalReference: Boolean;
  221. var
  222. i: Integer;
  223. s, p: PChar;
  224. begin
  225. i := Pos('.', FName);
  226. if i = 0 then
  227. exit(False);
  228. FRootName := Copy(FName, 1, i - 1);
  229. FName := Copy(FName, i + 1, Length(FName));
  230. Result := True;
  231. end;
  232. Type
  233. TInitHandler = Class(TObject)
  234. AHandler : TInitComponentHandler;
  235. AClass : TComponentClass;
  236. end;
  237. Var
  238. InitHandlerList : TList;
  239. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  240. Var
  241. I : Integer;
  242. H: TInitHandler;
  243. begin
  244. If (InitHandlerList=Nil) then
  245. InitHandlerList:=TList.Create;
  246. H:=TInitHandler.Create;
  247. H.Aclass:=ComponentClass;
  248. H.AHandler:=Handler;
  249. With InitHandlerList do
  250. begin
  251. I:=0;
  252. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[i]).AClass) do
  253. Inc(I);
  254. InitHandlerList.Insert(I,H);
  255. end;
  256. end;
  257. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  258. Var
  259. I : Integer;
  260. begin
  261. I:=0;
  262. Result:=False;
  263. With InitHandlerList do
  264. begin
  265. I:=0;
  266. // Instance is the normally the lowest one, so that one should be used when searching.
  267. While Not result and (I<Count) do
  268. begin
  269. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  270. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  271. Inc(I);
  272. end;
  273. end;
  274. end;
  275. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  276. begin
  277. { !!!: Too Win32-specific }
  278. InitComponentRes := False;
  279. end;
  280. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  281. begin
  282. { !!!: Too Win32-specific }
  283. ReadComponentRes := nil;
  284. end;
  285. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  286. begin
  287. { !!!: Too Win32-specific in VCL }
  288. ReadComponentResEx := nil;
  289. end;
  290. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  291. var
  292. FileStream: TStream;
  293. begin
  294. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  295. try
  296. Result := FileStream.ReadComponentRes(Instance);
  297. finally
  298. FileStream.Free;
  299. end;
  300. end;
  301. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  302. var
  303. FileStream: TStream;
  304. begin
  305. FileStream := TFileStream.Create(FileName, fmCreate);
  306. try
  307. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  308. finally
  309. FileStream.Free;
  310. end;
  311. end;
  312. procedure GlobalFixupReferences;
  313. var
  314. GlobalList, DoneList, ToDoList: TList;
  315. I, Index: Integer;
  316. Root: TComponent;
  317. Instance: TPersistent;
  318. Reference: Pointer;
  319. begin
  320. if not Assigned(FindGlobalComponent) then
  321. exit;
  322. {!!!: GlobalNameSpace.BeginWrite;
  323. try}
  324. GlobalList := GlobalFixupList.LockList;
  325. try
  326. if GlobalList.Count > 0 then
  327. begin
  328. ToDoList := nil;
  329. DoneList := TList.Create;
  330. ToDoList := TList.Create;
  331. try
  332. i := 0;
  333. while i < GlobalList.Count do
  334. with TPropFixup(GlobalList[i]) do
  335. begin
  336. Root := FindGlobalComponent(FRootName);
  337. if Assigned(Root) or (GetOrdProp(FInstance, FPropInfo) <> 0) then
  338. begin
  339. if Assigned(Root) then
  340. begin
  341. Reference := FindNestedComponent(Root, FName);
  342. SetOrdProp(FInstance, FPropInfo, Longint(Reference));
  343. end;
  344. // Move component to list of done components, if necessary
  345. if (DoneList.IndexOf(FInstance) < 0) and
  346. (ToDoList.IndexOf(FInstance) >= 0) then
  347. DoneList.Add(FInstance);
  348. GlobalList.Delete(i);
  349. Free; // ...the fixup
  350. end else
  351. begin
  352. // Move component to list of components to process, if necessary
  353. Index := DoneList.IndexOf(FInstance);
  354. if Index <> -1 then
  355. DoneList.Delete(Index);
  356. if ToDoList.IndexOf(FInstance) < 0 then
  357. ToDoList.Add(FInstance);
  358. Inc(i);
  359. end;
  360. end;
  361. for i := 0 to DoneList.Count - 1 do
  362. begin
  363. Instance := TPersistent(DoneList[I]);
  364. if Instance.InheritsFrom(TComponent) then
  365. Exclude(TComponent(Instance).FComponentState, csFixups);
  366. end;
  367. finally
  368. ToDoList.Free;
  369. DoneList.Free;
  370. end;
  371. end;
  372. finally
  373. GlobalFixupList.UnlockList;
  374. end;
  375. {finally
  376. GlobalNameSpace.EndWrite;
  377. end;}
  378. end;
  379. function IsStringInList(const AString: String; AList: TStrings): Boolean;
  380. var
  381. i: Integer;
  382. begin
  383. for i := 0 to AList.Count - 1 do
  384. if CompareText(AList[i], AString) = 0 then
  385. exit(True);
  386. Result := False;
  387. end;
  388. procedure GetFixupReferenceNames(Root: TComponent; Names: TStrings);
  389. var
  390. i: Integer;
  391. CurFixup: TPropFixup;
  392. begin
  393. with GlobalFixupList.LockList do
  394. try
  395. for i := 0 to Count - 1 do
  396. begin
  397. CurFixup := TPropFixup(Items[i]);
  398. if ((not Assigned(Root)) or (CurFixup.FInstanceRoot = Root)) and
  399. not IsStringInList(CurFixup.FRootName, Names) then
  400. Names.Add(CurFixup.FRootName);
  401. end;
  402. finally
  403. GlobalFixupList.UnlockList;
  404. end;
  405. end;
  406. procedure GetFixupInstanceNames(Root: TComponent;
  407. const ReferenceRootName: string; Names: TStrings);
  408. var
  409. i: Integer;
  410. CurFixup: TPropFixup;
  411. begin
  412. with GlobalFixupList.LockList do
  413. try
  414. for i := 0 to Count - 1 do
  415. begin
  416. CurFixup := TPropFixup(Items[i]);
  417. if (CurFixup.FInstanceRoot = Root) and
  418. (UpperCase(ReferenceRootName) = UpperCase(CurFixup.FRootName)) and
  419. not IsStringInList(CurFixup.FName, Names) then
  420. Names.Add(CurFixup.FName);
  421. end;
  422. finally
  423. GlobalFixupList.UnlockList;
  424. end;
  425. end;
  426. procedure RedirectFixupReferences(Root: TComponent; const OldRootName,
  427. NewRootName: string);
  428. var
  429. i: Integer;
  430. CurFixup: TPropFixup;
  431. begin
  432. with GlobalFixupList.LockList do
  433. try
  434. for i := 0 to Count - 1 do
  435. begin
  436. CurFixup := TPropFixup(Items[i]);
  437. if ((not Assigned(Root)) or (CurFixup.FInstanceRoot = Root)) and
  438. (UpperCase(OldRootName) = UpperCase(CurFixup.FRootName)) then
  439. CurFixup.FRootName := NewRootName;
  440. end;
  441. GlobalFixupReferences;
  442. finally
  443. GlobalFixupList.Unlocklist;
  444. end;
  445. end;
  446. procedure RemoveFixupReferences(Root: TComponent; const RootName: string);
  447. var
  448. i: Integer;
  449. CurFixup: TPropFixup;
  450. begin
  451. if not Assigned(GlobalFixupList) then
  452. exit;
  453. with GlobalFixupList.LockList do
  454. try
  455. for i := Count - 1 downto 0 do
  456. begin
  457. CurFixup := TPropFixup(Items[i]);
  458. if ((not Assigned(Root)) or (CurFixup.FInstanceRoot = Root)) and
  459. ((Length(RootName) = 0) or
  460. (UpperCase(RootName) = UpperCase(CurFixup.FRootName))) then
  461. begin
  462. Delete(i);
  463. CurFixup.Free;
  464. end;
  465. end;
  466. finally
  467. GlobalFixupList.UnlockList;
  468. end;
  469. end;
  470. procedure RemoveFixups(Instance: TPersistent);
  471. var
  472. i: Integer;
  473. CurFixup: TPropFixup;
  474. begin
  475. if not Assigned(GlobalFixupList) then
  476. exit;
  477. with GlobalFixupList.LockList do
  478. try
  479. for i := Count - 1 downto 0 do
  480. begin
  481. CurFixup := TPropFixup(Items[i]);
  482. if (CurFixup.FInstance = Instance) then
  483. begin
  484. Delete(i);
  485. CurFixup.Free;
  486. end;
  487. end;
  488. finally
  489. GlobalFixupList.UnlockList;
  490. end;
  491. end;
  492. function FindNestedComponent(Root: TComponent; const NamePath: string): TComponent;
  493. var
  494. Current, Found: TComponent;
  495. s, p: PChar;
  496. Name: String;
  497. begin
  498. Result := nil;
  499. if Length(NamePath) > 0 then
  500. begin
  501. Current := Root;
  502. p := PChar(NamePath);
  503. while p[0] <> #0 do
  504. begin
  505. s := p;
  506. while not (p^ in ['.', '-', #0]) do
  507. Inc(p);
  508. SetString(Name, s, p - s);
  509. Found := Current.FindComponent(Name);
  510. if (not Assigned(Found)) and (UpperCase(Name) = 'OWNER') then
  511. Found := Current;
  512. if not Assigned(Found) then exit;
  513. // Remove the dereference operator from the name
  514. if p[0] = '.' then
  515. Inc(P);
  516. if p[0] = '-' then
  517. Inc(P);
  518. if p[0] = '>' then
  519. Inc(P);
  520. Current := Found;
  521. end;
  522. end;
  523. Result := Current;
  524. end;
  525. {!!!: Should be threadvar - doesn't work for all platforms yet!}
  526. var
  527. GlobalLoaded, GlobalLists: TList;
  528. procedure BeginGlobalLoading;
  529. begin
  530. if not Assigned(GlobalLists) then
  531. GlobalLists := TList.Create;
  532. GlobalLists.Add(GlobalLoaded);
  533. GlobalLoaded := TList.Create;
  534. end;
  535. { Notify all global components that they have been loaded completely }
  536. procedure NotifyGlobalLoading;
  537. var
  538. i: Integer;
  539. begin
  540. for i := 0 to GlobalLoaded.Count - 1 do
  541. TComponent(GlobalLoaded[i]).Loaded;
  542. end;
  543. procedure EndGlobalLoading;
  544. begin
  545. { Free the memory occupied by BeginGlobalLoading }
  546. GlobalLoaded.Free;
  547. GlobalLoaded := TList(GlobalLists.Last);
  548. GlobalLists.Delete(GlobalLists.Count - 1);
  549. if GlobalLists.Count = 0 then
  550. begin
  551. GlobalLists.Free;
  552. GlobalLists := nil;
  553. end;
  554. end;
  555. function CollectionsEqual(C1, C2: TCollection): Boolean;
  556. begin
  557. // !!!: Implement this
  558. CollectionsEqual:=false;
  559. end;
  560. { Object conversion routines }
  561. procedure ObjectBinaryToText(Input, Output: TStream);
  562. procedure OutStr(s: String);
  563. begin
  564. if Length(s) > 0 then
  565. Output.Write(s[1], Length(s));
  566. end;
  567. procedure OutLn(s: String);
  568. begin
  569. OutStr(s + #10);
  570. end;
  571. procedure OutString(s: String);
  572. var
  573. res, NewStr: String;
  574. i: Integer;
  575. InString, NewInString: Boolean;
  576. begin
  577. res := '';
  578. InString := False;
  579. for i := 1 to Length(s) do begin
  580. NewInString := InString;
  581. case s[i] of
  582. #0..#31: begin
  583. if InString then
  584. NewInString := False;
  585. NewStr := '#' + IntToStr(Ord(s[i]));
  586. end;
  587. '''':
  588. if InString then NewStr := ''''''
  589. else NewStr := '''''''';
  590. else begin
  591. if not InString then
  592. NewInString := True;
  593. NewStr := s[i];
  594. end;
  595. end;
  596. if NewInString <> InString then begin
  597. NewStr := '''' + NewStr;
  598. InString := NewInString;
  599. end;
  600. res := res + NewStr;
  601. end;
  602. if InString then res := res + '''';
  603. OutStr(res);
  604. end;
  605. function ReadInt(ValueType: TValueType): LongInt;
  606. begin
  607. case ValueType of
  608. vaInt8: Result := ShortInt(Input.ReadByte);
  609. vaInt16: Result := SmallInt(Input.ReadWord);
  610. vaInt32: Result := LongInt(Input.ReadDWord);
  611. end;
  612. end;
  613. function ReadInt: LongInt;
  614. begin
  615. Result := ReadInt(TValueType(Input.ReadByte));
  616. end;
  617. function ReadSStr: String;
  618. var
  619. len: Byte;
  620. begin
  621. len := Input.ReadByte;
  622. SetLength(Result, len);
  623. Input.Read(Result[1], len);
  624. end;
  625. procedure ReadPropList(indent: String);
  626. procedure ProcessValue(ValueType: TValueType; Indent: String);
  627. procedure Stop(s: String);
  628. begin
  629. WriteLn(s);
  630. Halt;
  631. end;
  632. procedure ProcessBinary;
  633. var
  634. ToDo, DoNow, i: LongInt;
  635. lbuf: array[0..31] of Byte;
  636. s: String;
  637. begin
  638. ToDo := Input.ReadDWord;
  639. OutLn('{');
  640. while ToDo > 0 do begin
  641. DoNow := ToDo;
  642. if DoNow > 32 then DoNow := 32;
  643. Dec(ToDo, DoNow);
  644. s := Indent + ' ';
  645. Input.Read(lbuf, DoNow);
  646. for i := 0 to DoNow - 1 do
  647. s := s + IntToHex(lbuf[i], 2);
  648. OutLn(s);
  649. end;
  650. OutLn(indent + '}');
  651. end;
  652. var
  653. s: String;
  654. len: LongInt;
  655. IsFirst: Boolean;
  656. ext: Extended;
  657. begin
  658. case ValueType of
  659. vaList: begin
  660. OutStr('(');
  661. IsFirst := True;
  662. while True do begin
  663. ValueType := TValueType(Input.ReadByte);
  664. if ValueType = vaNull then break;
  665. if IsFirst then begin
  666. OutLn('');
  667. IsFirst := False;
  668. end;
  669. OutStr(Indent + ' ');
  670. ProcessValue(ValueType, Indent + ' ');
  671. end;
  672. OutLn(Indent + ')');
  673. end;
  674. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  675. vaInt16: OutLn( IntToStr(SmallInt(Input.ReadWord)));
  676. vaInt32: OutLn(IntToStr(LongInt(Input.ReadDWord)));
  677. vaExtended: begin
  678. Input.Read(ext, SizeOf(ext));
  679. OutLn(FloatToStr(ext));
  680. end;
  681. vaString: begin
  682. OutString(ReadSStr);
  683. OutLn('');
  684. end;
  685. vaIdent: OutLn(ReadSStr);
  686. vaFalse: OutLn('False');
  687. vaTrue: OutLn('True');
  688. vaBinary: ProcessBinary;
  689. vaSet: begin
  690. OutStr('[');
  691. IsFirst := True;
  692. while True do begin
  693. s := ReadSStr;
  694. if Length(s) = 0 then break;
  695. if not IsFirst then OutStr(', ');
  696. IsFirst := False;
  697. OutStr(s);
  698. end;
  699. OutLn(']');
  700. end;
  701. vaLString:
  702. Stop('!!LString!!');
  703. vaNil:
  704. OutLn('nil');
  705. vaCollection: begin
  706. OutStr('<');
  707. while Input.ReadByte <> 0 do begin
  708. OutLn(Indent);
  709. Input.Seek(-1, soFromCurrent);
  710. OutStr(indent + ' item');
  711. ValueType := TValueType(Input.ReadByte);
  712. if ValueType <> vaList then
  713. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  714. OutLn('');
  715. ReadPropList(indent + ' ');
  716. OutStr(indent + ' end');
  717. end;
  718. OutLn('>');
  719. end;
  720. {vaSingle: begin OutLn('!!Single!!'); exit end;
  721. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  722. vaDate: begin OutLn('!!Date!!'); exit end;
  723. vaWString: begin OutLn('!!WString!!'); exit end;}
  724. else
  725. Stop(IntToStr(Ord(ValueType)));
  726. end;
  727. end;
  728. begin
  729. while Input.ReadByte <> 0 do begin
  730. Input.Seek(-1, soFromCurrent);
  731. OutStr(indent + ReadSStr + ' = ');
  732. ProcessValue(TValueType(Input.ReadByte), Indent);
  733. end;
  734. end;
  735. procedure ReadObject(indent: String);
  736. var
  737. b: Byte;
  738. ObjClassName, ObjName: String;
  739. ChildPos: LongInt;
  740. begin
  741. // Check for FilerFlags
  742. b := Input.ReadByte;
  743. if (b and $f0) = $f0 then begin
  744. if (b and 2) <> 0 then ChildPos := ReadInt;
  745. end else begin
  746. b := 0;
  747. Input.Seek(-1, soFromCurrent);
  748. end;
  749. ObjClassName := ReadSStr;
  750. ObjName := ReadSStr;
  751. OutStr(Indent);
  752. if (b and 1) <> 0 then OutStr('inherited')
  753. else OutStr('object');
  754. OutStr(' ');
  755. if ObjName <> '' then
  756. OutStr(ObjName + ': ');
  757. OutStr(ObjClassName);
  758. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  759. OutLn('');
  760. ReadPropList(indent + ' ');
  761. while Input.ReadByte <> 0 do begin
  762. Input.Seek(-1, soFromCurrent);
  763. ReadObject(indent + ' ');
  764. end;
  765. OutLn(indent + 'end');
  766. end;
  767. type
  768. PLongWord = ^LongWord;
  769. const
  770. signature: PChar = 'TPF0';
  771. begin
  772. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  773. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  774. ReadObject('');
  775. end;
  776. procedure ObjectTextToBinary(Input, Output: TStream);
  777. var
  778. parser: TParser;
  779. procedure WriteString(s: String);
  780. begin
  781. Output.WriteByte(Length(s));
  782. if Length(s) > 0 then
  783. Output.Write(s[1], Length(s));
  784. end;
  785. procedure WriteInteger(value: LongInt);
  786. begin
  787. if (value >= -128) and (value <= 127) then begin
  788. Output.WriteByte(Ord(vaInt8));
  789. Output.WriteByte(Byte(value));
  790. end else if (value >= -32768) and (value <= 32767) then begin
  791. Output.WriteByte(Ord(vaInt16));
  792. Output.WriteWord(Word(value));
  793. end else begin
  794. Output.WriteByte(ord(vaInt32));
  795. Output.WriteDWord(LongWord(value));
  796. end;
  797. end;
  798. procedure ProcessProperty; forward;
  799. procedure ProcessValue;
  800. var
  801. flt: Extended;
  802. s: String;
  803. stream: TMemoryStream;
  804. begin
  805. case parser.Token of
  806. toInteger:
  807. begin
  808. WriteInteger(parser.TokenInt);
  809. parser.NextToken;
  810. end;
  811. toFloat:
  812. begin
  813. Output.WriteByte(Ord(vaExtended));
  814. flt := Parser.TokenFloat;
  815. Output.Write(flt, SizeOf(flt));
  816. parser.NextToken;
  817. end;
  818. toString:
  819. begin
  820. s := parser.TokenString;
  821. while parser.NextToken = '+' do
  822. begin
  823. parser.NextToken; // Get next string fragment
  824. parser.CheckToken(toString);
  825. s := s + parser.TokenString;
  826. end;
  827. Output.WriteByte(Ord(vaString));
  828. WriteString(s);
  829. end;
  830. toSymbol:
  831. begin
  832. if CompareText(parser.TokenString, 'True') = 0 then
  833. Output.WriteByte(Ord(vaTrue))
  834. else if CompareText(parser.TokenString, 'False') = 0 then
  835. Output.WriteByte(Ord(vaFalse))
  836. else if CompareText(parser.TokenString, 'nil') = 0 then
  837. Output.WriteByte(Ord(vaNil))
  838. else
  839. begin
  840. Output.WriteByte(Ord(vaIdent));
  841. WriteString(parser.TokenComponentIdent);
  842. end;
  843. Parser.NextToken;
  844. end;
  845. // Set
  846. '[':
  847. begin
  848. parser.NextToken;
  849. Output.WriteByte(Ord(vaSet));
  850. if parser.Token <> ']' then
  851. while True do
  852. begin
  853. parser.CheckToken(toSymbol);
  854. WriteString(parser.TokenString);
  855. parser.NextToken;
  856. if parser.Token = ']' then
  857. break;
  858. parser.CheckToken(',');
  859. parser.NextToken;
  860. end;
  861. Output.WriteByte(0);
  862. parser.NextToken;
  863. end;
  864. // List
  865. '(':
  866. begin
  867. parser.NextToken;
  868. Output.WriteByte(Ord(vaList));
  869. while parser.Token <> ')' do
  870. ProcessValue;
  871. Output.WriteByte(0);
  872. parser.NextToken;
  873. end;
  874. // Collection
  875. '<':
  876. begin
  877. parser.NextToken;
  878. Output.WriteByte(Ord(vaCollection));
  879. while parser.Token <> '>' do
  880. begin
  881. parser.CheckTokenSymbol('item');
  882. parser.NextToken;
  883. // ConvertOrder
  884. Output.WriteByte(Ord(vaList));
  885. while not parser.TokenSymbolIs('end') do
  886. ProcessProperty;
  887. parser.NextToken; // Skip 'end'
  888. Output.WriteByte(0);
  889. end;
  890. Output.WriteByte(0);
  891. parser.NextToken;
  892. end;
  893. // Binary data
  894. '{':
  895. begin
  896. Output.WriteByte(Ord(vaBinary));
  897. stream := TMemoryStream.Create;
  898. try
  899. parser.HexToBinary(stream);
  900. Output.WriteDWord(stream.Size);
  901. Output.Write(Stream.Memory^, stream.Size);
  902. finally
  903. stream.Free;
  904. end;
  905. parser.NextToken;
  906. end;
  907. else
  908. parser.Error(SInvalidProperty);
  909. end;
  910. end;
  911. procedure ProcessProperty;
  912. var
  913. name: String;
  914. begin
  915. // Get name of property
  916. parser.CheckToken(toSymbol);
  917. name := parser.TokenString;
  918. while True do begin
  919. parser.NextToken;
  920. if parser.Token <> '.' then break;
  921. parser.NextToken;
  922. parser.CheckToken(toSymbol);
  923. name := name + '.' + parser.TokenString;
  924. end;
  925. WriteString(name);
  926. parser.CheckToken('=');
  927. parser.NextToken;
  928. ProcessValue;
  929. end;
  930. procedure ProcessObject;
  931. var
  932. IsInherited: Boolean;
  933. ObjectName, ObjectType: String;
  934. begin
  935. if parser.TokenSymbolIs('OBJECT') then
  936. IsInherited := False
  937. else begin
  938. parser.CheckTokenSymbol('INHERITED');
  939. IsInherited := True;
  940. end;
  941. parser.NextToken;
  942. parser.CheckToken(toSymbol);
  943. ObjectName := '';
  944. ObjectType := parser.TokenString;
  945. parser.NextToken;
  946. if parser.Token = ':' then begin
  947. parser.NextToken;
  948. parser.CheckToken(toSymbol);
  949. ObjectName := ObjectType;
  950. ObjectType := parser.TokenString;
  951. parser.NextToken;
  952. end;
  953. WriteString(ObjectType);
  954. WriteString(ObjectName);
  955. // Convert property list
  956. while not (parser.TokenSymbolIs('END') or
  957. parser.TokenSymbolIs('OBJECT') or
  958. parser.TokenSymbolIs('INHERITED')) do
  959. ProcessProperty;
  960. Output.WriteByte(0); // Terminate property list
  961. // Convert child objects
  962. while not parser.TokenSymbolIs('END') do ProcessObject;
  963. parser.NextToken; // Skip end token
  964. Output.WriteByte(0); // Terminate property list
  965. end;
  966. const
  967. signature: PChar = 'TPF0';
  968. begin
  969. parser := TParser.Create(Input);
  970. try
  971. Output.Write(signature[0], 4);
  972. ProcessObject;
  973. finally
  974. parser.Free;
  975. end;
  976. end;
  977. procedure ObjectResourceToText(Input, Output: TStream);
  978. begin
  979. Input.ReadResHeader;
  980. ObjectBinaryToText(Input, Output);
  981. end;
  982. procedure ObjectTextToResource(Input, Output: TStream);
  983. var
  984. StartPos, SizeStartPos, BinSize: LongInt;
  985. parser: TParser;
  986. name: String;
  987. begin
  988. // Get form type name
  989. StartPos := Input.Position;
  990. parser := TParser.Create(Input);
  991. try
  992. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  993. parser.NextToken;
  994. parser.CheckToken(toSymbol);
  995. parser.NextToken;
  996. parser.CheckToken(':');
  997. parser.NextToken;
  998. parser.CheckToken(toSymbol);
  999. name := parser.TokenString;
  1000. finally
  1001. parser.Free;
  1002. Input.Position := StartPos;
  1003. end;
  1004. // Write resource header
  1005. name := UpperCase(name);
  1006. Output.WriteByte($ff);
  1007. Output.WriteByte(10);
  1008. Output.WriteByte(0);
  1009. Output.Write(name[1], Length(name) + 1); // Write null-terminated form type name
  1010. Output.WriteWord($1030);
  1011. SizeStartPos := Output.Position;
  1012. Output.WriteDWord(0); // Placeholder for data size
  1013. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1014. BinSize := Output.Position - SizeStartPos - 4;
  1015. Output.Position := SizeStartPos;
  1016. Output.WriteDWord(BinSize); // Insert real resource data size
  1017. end;
  1018. { Utility routines }
  1019. function LineStart(Buffer, BufPos: PChar): PChar;
  1020. begin
  1021. Result := BufPos;
  1022. while Result > Buffer do begin
  1023. Dec(Result);
  1024. if Result[0] = #10 then break;
  1025. end;
  1026. end;
  1027. procedure CommonInit;
  1028. begin
  1029. InitHandlerList:=Nil;
  1030. IntConstList := TThreadList.Create;
  1031. GlobalFixupList := TThreadList.Create;
  1032. ClassList := TThreadList.Create;
  1033. ClassAliasList := TStringList.Create;
  1034. end;
  1035. procedure CommonCleanup;
  1036. var
  1037. i: Integer;
  1038. begin
  1039. // !!!: GlobalNameSpace.BeginWrite;
  1040. with IntConstList.LockList do
  1041. try
  1042. for i := 0 to Count - 1 do
  1043. TIntConst(Items[I]).Free;
  1044. finally
  1045. IntConstList.UnlockList;
  1046. end;
  1047. IntConstList.Free;
  1048. ClassList.Free;
  1049. ClassAliasList.Free;
  1050. RemoveFixupReferences(nil, '');
  1051. GlobalFixupList.Free;
  1052. GlobalFixupList := nil;
  1053. GlobalLists.Free;
  1054. ComponentPages.Free;
  1055. {!!!: GlobalNameSpace.Free;
  1056. GlobalNameSpace := nil;}
  1057. InitHandlerList.Free;
  1058. InitHandlerList:=Nil;
  1059. end;
  1060. { TFiler implementation }
  1061. {$i filer.inc}
  1062. { TReader implementation }
  1063. {$i reader.inc}
  1064. { TWriter implementations }
  1065. {$i writer.inc}
  1066. {$i twriter.inc}
  1067. {
  1068. $Log$
  1069. Revision 1.2 2003-12-15 08:57:24 michael
  1070. Patch from Darek Mazur for reading idents from property stream
  1071. Revision 1.3 2003/12/15 08:55:56 michael
  1072. Patch from Darek Mazur for reading idents from property stream
  1073. Revision 1.2 2003/11/19 15:51:54 peter
  1074. * tthread disabled for 1.0.x
  1075. Revision 1.1 2003/10/06 21:01:06 peter
  1076. * moved classes unit to rtl
  1077. Revision 1.14 2003/06/04 17:40:44 michael
  1078. + Minor fix by Mattias Gaertner
  1079. Revision 1.13 2003/06/04 15:27:24 michael
  1080. + TDataModule en InitInheritedComponent erbij voor Delphi 6 compatibility
  1081. Revision 1.12 2003/04/19 14:29:25 michael
  1082. + Fix from Mattias Gaertner, closes memory leak
  1083. Revision 1.11 2002/12/02 12:04:07 sg
  1084. * Fixed handling of zero-length strings (classes.inc: When converting
  1085. empty strings from text forms to binary forms; reader.inc: When reading
  1086. an empty string from a binary serialization)
  1087. Revision 1.10 2002/09/07 15:15:24 peter
  1088. * old logs removed and tabs fixed
  1089. Revision 1.9 2002/07/16 13:32:51 florian
  1090. + skeleton for TInterfaceList added
  1091. Revision 1.8 2002/01/06 21:54:49 peter
  1092. * action classes added
  1093. }