classes.inc 28 KB

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