classes.inc 29 KB

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