classes.inc 29 KB

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