classes.inc 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {**********************************************************************
  11. * Class implementations are in separate files. *
  12. **********************************************************************}
  13. var
  14. ClassList : TThreadlist;
  15. ClassAliasList : TStringList;
  16. {
  17. Include all message strings
  18. Add a language with IFDEF LANG_NAME
  19. just befor the final ELSE. This way English will always be the default.
  20. }
  21. {$IFDEF LANG_GERMAN}
  22. {$i constsg.inc}
  23. {$ELSE}
  24. {$IFDEF LANG_SPANISH}
  25. {$i constss.inc}
  26. {$ENDIF}
  27. {$ENDIF}
  28. { Utility routines }
  29. {$i util.inc}
  30. { TBits implementation }
  31. {$i bits.inc}
  32. { All streams implementations: }
  33. { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
  34. { TCustomMemoryStream TMemoryStream }
  35. {$i streams.inc}
  36. { TParser implementation}
  37. {$i parser.inc}
  38. { TCollection and TCollectionItem implementations }
  39. {$i collect.inc}
  40. { TList and TThreadList implementations }
  41. {$i lists.inc}
  42. { TStrings and TStringList implementations }
  43. {$i stringl.inc}
  44. { TThread implementation }
  45. { system independend threading code }
  46. var
  47. { event that happens when gui thread is done executing the method}
  48. ExecuteEvent: PRtlEvent;
  49. { event executed by synchronize to wake main thread if it sleeps in CheckSynchronize }
  50. SynchronizeTimeoutEvent: PRtlEvent;
  51. { guard for synchronization variables }
  52. SynchronizeCritSect: TRtlCriticalSection;
  53. { method to execute }
  54. SynchronizeMethod: TThreadMethod;
  55. { should we execute the method? }
  56. DoSynchronizeMethod: boolean;
  57. { caught exception in gui thread, to be raised in calling thread }
  58. SynchronizeException: Exception;
  59. function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
  60. var
  61. FreeThread: Boolean;
  62. Thread: TThread absolute ThreadObjPtr;
  63. begin
  64. { if Suspend checks FSuspended before doing anything, make sure it }
  65. { knows we're currently not suspended (this flag may have been set }
  66. { to true if CreateSuspended was true) }
  67. // Thread.FSuspended:=false;
  68. // wait until AfterConstruction has been called, so we cannot
  69. // free ourselves before TThread.Create has finished
  70. // (since that one may check our VTM in case of $R+, and
  71. // will call the AfterConstruction method in all cases)
  72. // Thread.Suspend;
  73. try
  74. Thread.Execute;
  75. except
  76. Thread.FFatalException := TObject(AcquireExceptionObject);
  77. end;
  78. FreeThread := Thread.FFreeOnTerminate;
  79. Result := Thread.FReturnValue;
  80. Thread.FFinished := True;
  81. Thread.DoTerminate;
  82. if FreeThread then
  83. Thread.Free;
  84. EndThread(Result);
  85. end;
  86. { system-dependent code }
  87. {$i tthread.inc}
  88. procedure TThread.Start;
  89. begin
  90. { suspend/resume are now deprecated in Delphi (they also don't work
  91. on most platforms in FPC), so a different method was required
  92. to start a thread if it's create with fSuspended=true -> that's
  93. what this method is for. }
  94. Resume;
  95. end;
  96. function TThread.GetSuspended: Boolean;
  97. begin
  98. GetSuspended:=FSuspended;
  99. end;
  100. procedure TThread.AfterConstruction;
  101. begin
  102. inherited AfterConstruction;
  103. // enable for all platforms once http://bugs.freepascal.org/view.php?id=16884
  104. // is fixed for all platforms (in case the fix for non-unix platforms also
  105. // requires this field at least)
  106. {$ifdef unix}
  107. if not FInitialSuspended then
  108. Resume;
  109. {$endif}
  110. end;
  111. class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
  112. var
  113. LocalSyncException: Exception;
  114. begin
  115. { do we really need a synchronized call? }
  116. if GetCurrentThreadID=MainThreadID then
  117. AMethod()
  118. else
  119. begin
  120. System.EnterCriticalSection(SynchronizeCritSect);
  121. SynchronizeException:=nil;
  122. SynchronizeMethod:=AMethod;
  123. { be careful, after this assignment Method could be already executed }
  124. DoSynchronizeMethod:=true;
  125. RtlEventSetEvent(SynchronizeTimeoutEvent);
  126. if assigned(WakeMainThread) then
  127. WakeMainThread(AThread);
  128. { wait infinitely }
  129. RtlEventWaitFor(ExecuteEvent);
  130. LocalSyncException:=SynchronizeException;
  131. System.LeaveCriticalSection(SynchronizeCritSect);
  132. if assigned(LocalSyncException) then
  133. raise LocalSyncException;
  134. end;
  135. end;
  136. procedure TThread.Synchronize(AMethod: TThreadMethod);
  137. begin
  138. TThread.Synchronize(self,AMethod);
  139. end;
  140. function CheckSynchronize(timeout : longint=0) : boolean;
  141. { assumes being called from GUI thread }
  142. begin
  143. result:=false;
  144. { first sanity check }
  145. if Not IsMultiThread then
  146. Exit
  147. { second sanity check }
  148. else if GetCurrentThreadID<>MainThreadID then
  149. raise EThread.CreateFmt(SCheckSynchronizeError,[GetCurrentThreadID])
  150. else
  151. begin
  152. if timeout>0 then
  153. begin
  154. RtlEventWaitFor(SynchronizeTimeoutEvent,timeout);
  155. end
  156. else
  157. RtlEventResetEvent(SynchronizeTimeoutEvent);
  158. if DoSynchronizeMethod then
  159. begin
  160. DoSynchronizeMethod:=false;
  161. try
  162. SynchronizeMethod;
  163. result:=true;
  164. except
  165. SynchronizeException:=Exception(AcquireExceptionObject);
  166. end;
  167. RtlEventSetEvent(ExecuteEvent);
  168. end;
  169. end;
  170. end;
  171. { TPersistent implementation }
  172. {$i persist.inc }
  173. {$i sllist.inc}
  174. {$i resref.inc}
  175. { TComponent implementation }
  176. {$i compon.inc}
  177. { TBasicAction implementation }
  178. {$i action.inc}
  179. { TDataModule implementation }
  180. {$i dm.inc}
  181. { Class and component registration routines }
  182. {$I cregist.inc}
  183. { Interface related stuff }
  184. {$I intf.inc}
  185. {**********************************************************************
  186. * Miscellaneous procedures and functions *
  187. **********************************************************************}
  188. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings): Integer;
  189. var
  190. b, c : pchar;
  191. procedure SkipWhitespace;
  192. begin
  193. while (c^ in Whitespace) do
  194. inc (c);
  195. end;
  196. procedure AddString;
  197. var
  198. l : integer;
  199. s : string;
  200. begin
  201. l := c-b;
  202. if l > 0 then
  203. begin
  204. if assigned(Strings) then
  205. begin
  206. setlength(s, l);
  207. move (b^, s[1],l);
  208. Strings.Add (s);
  209. end;
  210. inc (result);
  211. end;
  212. end;
  213. var
  214. quoted : char;
  215. begin
  216. result := 0;
  217. c := Content;
  218. Quoted := #0;
  219. Separators := Separators + [#13, #10] - ['''','"'];
  220. SkipWhitespace;
  221. b := c;
  222. while (c^ <> #0) do
  223. begin
  224. if (c^ = Quoted) then
  225. begin
  226. if ((c+1)^ = Quoted) then
  227. inc (c)
  228. else
  229. Quoted := #0
  230. end
  231. else if (Quoted = #0) and (c^ in ['''','"']) then
  232. Quoted := c^;
  233. if (Quoted = #0) and (c^ in Separators) then
  234. begin
  235. AddString;
  236. inc (c);
  237. SkipWhitespace;
  238. b := c;
  239. end
  240. else
  241. inc (c);
  242. end;
  243. if (c <> b) then
  244. AddString;
  245. end;
  246. { Point and rectangle constructors }
  247. function Point(AX, AY: Integer): TPoint;
  248. begin
  249. with Result do
  250. begin
  251. X := AX;
  252. Y := AY;
  253. end;
  254. end;
  255. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  256. begin
  257. with Result do
  258. begin
  259. X := AX;
  260. Y := AY;
  261. end;
  262. end;
  263. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  264. begin
  265. with Result do
  266. begin
  267. Left := ALeft;
  268. Top := ATop;
  269. Right := ARight;
  270. Bottom := ABottom;
  271. end;
  272. end;
  273. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  274. begin
  275. with Result do
  276. begin
  277. Left := ALeft;
  278. Top := ATop;
  279. Right := ALeft + AWidth;
  280. Bottom := ATop + AHeight;
  281. end;
  282. end;
  283. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  284. begin
  285. { lazy, but should work }
  286. result:=QWord(P1)=QWord(P2);
  287. end;
  288. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  289. begin
  290. { lazy, but should work }
  291. result:=DWord(P1)=DWord(P2);
  292. end;
  293. function InvalidPoint(X, Y: Integer): Boolean;
  294. begin
  295. result:=(X=-1) and (Y=-1);
  296. end;
  297. function InvalidPoint(const At: TPoint): Boolean;
  298. begin
  299. result:=(At.x=-1) and (At.y=-1);
  300. end;
  301. function InvalidPoint(const At: TSmallPoint): Boolean;
  302. begin
  303. result:=(At.x=-1) and (At.y=-1);
  304. end;
  305. { Object filing routines }
  306. var
  307. IntConstList: TThreadList;
  308. type
  309. TIntConst = class
  310. IntegerType: PTypeInfo; // The integer type RTTI pointer
  311. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  312. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  313. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  314. AIntToIdent: TIntToIdent);
  315. end;
  316. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  317. AIntToIdent: TIntToIdent);
  318. begin
  319. IntegerType := AIntegerType;
  320. IdentToIntFn := AIdentToInt;
  321. IntToIdentFn := AIntToIdent;
  322. end;
  323. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  324. IntToIdentFn: TIntToIdent);
  325. begin
  326. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  327. end;
  328. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  329. var
  330. i: Integer;
  331. begin
  332. with IntConstList.LockList do
  333. try
  334. for i := 0 to Count - 1 do
  335. if TIntConst(Items[i]).IntegerType = AIntegerType then
  336. exit(TIntConst(Items[i]).IntToIdentFn);
  337. Result := nil;
  338. finally
  339. IntConstList.UnlockList;
  340. end;
  341. end;
  342. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  343. var
  344. i: Integer;
  345. begin
  346. with IntConstList.LockList do
  347. try
  348. for i := 0 to Count - 1 do
  349. with TIntConst(Items[I]) do
  350. if TIntConst(Items[I]).IntegerType = AIntegerType then
  351. exit(IdentToIntFn);
  352. Result := nil;
  353. finally
  354. IntConstList.UnlockList;
  355. end;
  356. end;
  357. function IdentToInt(const Ident: String; var Int: LongInt;
  358. const Map: array of TIdentMapEntry): Boolean;
  359. var
  360. i: Integer;
  361. begin
  362. for i := Low(Map) to High(Map) do
  363. if CompareText(Map[i].Name, Ident) = 0 then
  364. begin
  365. Int := Map[i].Value;
  366. exit(True);
  367. end;
  368. Result := False;
  369. end;
  370. function IntToIdent(Int: LongInt; var Ident: String;
  371. const Map: array of TIdentMapEntry): Boolean;
  372. var
  373. i: Integer;
  374. begin
  375. for i := Low(Map) to High(Map) do
  376. if Map[i].Value = Int then
  377. begin
  378. Ident := Map[i].Name;
  379. exit(True);
  380. end;
  381. Result := False;
  382. end;
  383. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  384. var
  385. i : Integer;
  386. begin
  387. with IntConstList.LockList do
  388. try
  389. for i := 0 to Count - 1 do
  390. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  391. Exit(True);
  392. Result := false;
  393. finally
  394. IntConstList.UnlockList;
  395. end;
  396. end;
  397. { TPropFixup }
  398. // Tainted. TPropFixup is being removed.
  399. Type
  400. TInitHandler = Class(TObject)
  401. AHandler : TInitComponentHandler;
  402. AClass : TComponentClass;
  403. end;
  404. Var
  405. InitHandlerList : TList;
  406. FindGlobalComponentList : TList;
  407. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  408. begin
  409. if not(assigned(FindGlobalComponentList)) then
  410. FindGlobalComponentList:=TList.Create;
  411. if FindGlobalComponentList.IndexOf(Pointer(AFindGlobalComponent))<0 then
  412. FindGlobalComponentList.Add(Pointer(AFindGlobalComponent));
  413. end;
  414. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  415. begin
  416. if assigned(FindGlobalComponentList) then
  417. FindGlobalComponentList.Remove(Pointer(AFindGlobalComponent));
  418. end;
  419. function FindGlobalComponent(const Name: string): TComponent;
  420. var
  421. i : sizeint;
  422. begin
  423. FindGlobalComponent:=nil;
  424. if assigned(FindGlobalComponentList) then
  425. begin
  426. for i:=FindGlobalComponentList.Count-1 downto 0 do
  427. begin
  428. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  429. if assigned(FindGlobalComponent) then
  430. break;
  431. end;
  432. end;
  433. end;
  434. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  435. Var
  436. I : Integer;
  437. H: TInitHandler;
  438. begin
  439. If (InitHandlerList=Nil) then
  440. InitHandlerList:=TList.Create;
  441. H:=TInitHandler.Create;
  442. H.Aclass:=ComponentClass;
  443. H.AHandler:=Handler;
  444. try
  445. With InitHandlerList do
  446. begin
  447. I:=0;
  448. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  449. Inc(I);
  450. { override? }
  451. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  452. begin
  453. TInitHandler(Items[I]).AHandler:=Handler;
  454. H.Free;
  455. end
  456. else
  457. InitHandlerList.Insert(I,H);
  458. end;
  459. except
  460. H.Free;
  461. raise;
  462. end;
  463. end;
  464. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  465. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  466. var
  467. ResStream : TResourceStream;
  468. begin
  469. result:=true;
  470. if Inst=0 then
  471. Inst:=HInstance;
  472. try
  473. ResStream:=TResourceStream.Create(Inst,res,RT_RCDATA);
  474. try
  475. Component:=ResStream.ReadComponent(Component);
  476. finally
  477. ResStream.Free;
  478. end;
  479. except
  480. on EResNotFound do
  481. result:=false;
  482. end;
  483. end;
  484. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  485. function doinit(_class : TClass) : boolean;
  486. begin
  487. result:=false;
  488. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  489. exit;
  490. result:=doinit(_class.ClassParent);
  491. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  492. end;
  493. begin
  494. GlobalNameSpace.BeginWrite;
  495. try
  496. result:=doinit(Instance.ClassType);
  497. finally
  498. GlobalNameSpace.EndWrite;
  499. end;
  500. end;
  501. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  502. Var
  503. I : Integer;
  504. begin
  505. I:=0;
  506. if not Assigned(InitHandlerList) then begin
  507. Result := True;
  508. Exit;
  509. end;
  510. Result:=False;
  511. With InitHandlerList do
  512. begin
  513. I:=0;
  514. // Instance is the normally the lowest one, so that one should be used when searching.
  515. While Not result and (I<Count) do
  516. begin
  517. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  518. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  519. Inc(I);
  520. end;
  521. end;
  522. end;
  523. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  524. begin
  525. { !!!: Too Win32-specific }
  526. InitComponentRes := False;
  527. end;
  528. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  529. begin
  530. { !!!: Too Win32-specific }
  531. ReadComponentRes := nil;
  532. end;
  533. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  534. begin
  535. { !!!: Too Win32-specific in VCL }
  536. ReadComponentResEx := nil;
  537. end;
  538. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  539. var
  540. FileStream: TStream;
  541. begin
  542. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  543. try
  544. Result := FileStream.ReadComponentRes(Instance);
  545. finally
  546. FileStream.Free;
  547. end;
  548. end;
  549. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  550. var
  551. FileStream: TStream;
  552. begin
  553. FileStream := TFileStream.Create(FileName, fmCreate);
  554. try
  555. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  556. finally
  557. FileStream.Free;
  558. end;
  559. end;
  560. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  561. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  562. Var
  563. P : Integer;
  564. CM : Boolean;
  565. begin
  566. P:=Pos('.',APath);
  567. CM:=False;
  568. If (P=0) then
  569. begin
  570. If CStyle then
  571. begin
  572. P:=Pos('->',APath);
  573. CM:=P<>0;
  574. end;
  575. If (P=0) Then
  576. P:=Length(APath)+1;
  577. end;
  578. Result:=Copy(APath,1,P-1);
  579. Delete(APath,1,P+Ord(CM));
  580. end;
  581. Var
  582. C : TComponent;
  583. S : String;
  584. begin
  585. If (APath='') then
  586. Result:=Nil
  587. else
  588. begin
  589. Result:=Root;
  590. While (APath<>'') And (Result<>Nil) do
  591. begin
  592. C:=Result;
  593. S:=Uppercase(GetNextName);
  594. Result:=C.FindComponent(S);
  595. If (Result=Nil) And (S='OWNER') then
  596. Result:=C;
  597. end;
  598. end;
  599. end;
  600. threadvar
  601. GlobalLoaded, GlobalLists: TList;
  602. procedure BeginGlobalLoading;
  603. begin
  604. if not Assigned(GlobalLists) then
  605. GlobalLists := TList.Create;
  606. GlobalLists.Add(GlobalLoaded);
  607. GlobalLoaded := TList.Create;
  608. end;
  609. { Notify all global components that they have been loaded completely }
  610. procedure NotifyGlobalLoading;
  611. var
  612. i: Integer;
  613. begin
  614. for i := 0 to GlobalLoaded.Count - 1 do
  615. TComponent(GlobalLoaded[i]).Loaded;
  616. end;
  617. procedure EndGlobalLoading;
  618. begin
  619. { Free the memory occupied by BeginGlobalLoading }
  620. GlobalLoaded.Free;
  621. GlobalLoaded := TList(GlobalLists.Last);
  622. GlobalLists.Delete(GlobalLists.Count - 1);
  623. if GlobalLists.Count = 0 then
  624. begin
  625. GlobalLists.Free;
  626. GlobalLists := nil;
  627. end;
  628. end;
  629. function CollectionsEqual(C1, C2: TCollection): Boolean;
  630. begin
  631. // !!!: Implement this
  632. CollectionsEqual:=false;
  633. end;
  634. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  635. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  636. var
  637. w : twriter;
  638. begin
  639. w:=twriter.create(s,4096);
  640. try
  641. w.root:=o;
  642. w.flookuproot:=o;
  643. w.writecollection(c);
  644. finally
  645. w.free;
  646. end;
  647. end;
  648. var
  649. s1,s2 : tmemorystream;
  650. begin
  651. result:=false;
  652. if (c1.classtype<>c2.classtype) or
  653. (c1.count<>c2.count) then
  654. exit;
  655. if c1.count = 0 then
  656. begin
  657. result:= true;
  658. exit;
  659. end;
  660. s1:=tmemorystream.create;
  661. try
  662. s2:=tmemorystream.create;
  663. try
  664. stream_collection(s1,c1,owner1);
  665. stream_collection(s2,c2,owner2);
  666. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  667. finally
  668. s2.free;
  669. end;
  670. finally
  671. s1.free;
  672. end;
  673. end;
  674. { Object conversion routines }
  675. type
  676. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  677. function CharToOrd(var P: Pointer): Cardinal;
  678. begin
  679. result:= ord(pchar(P)^);
  680. inc(pchar(P));
  681. end;
  682. function WideCharToOrd(var P: Pointer): Cardinal;
  683. begin
  684. result:= ord(pwidechar(P)^);
  685. inc(pwidechar(P));
  686. end;
  687. function Utf8ToOrd(var P:Pointer): Cardinal;
  688. begin
  689. // Should also check for illegal utf8 combinations
  690. Result := Ord(PChar(P)^);
  691. Inc(P);
  692. if (Result and $80) <> 0 then
  693. if (Ord(Result) and %11100000) = %11000000 then begin
  694. Result := ((Result and %00011111) shl 6)
  695. or (ord(PChar(P)^) and %00111111);
  696. Inc(P);
  697. end else if (Ord(Result) and %11110000) = %11100000 then begin
  698. Result := ((Result and %00011111) shl 12)
  699. or ((ord(PChar(P)^) and %00111111) shl 6)
  700. or (ord((PChar(P)+1)^) and %00111111);
  701. Inc(P,2);
  702. end else begin
  703. Result := ((ord(Result) and %00011111) shl 18)
  704. or ((ord(PChar(P)^) and %00111111) shl 12)
  705. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  706. or (ord((PChar(P)+2)^) and %00111111);
  707. Inc(P,3);
  708. end;
  709. end;
  710. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  711. procedure OutStr(s: String);
  712. begin
  713. if Length(s) > 0 then
  714. Output.Write(s[1], Length(s));
  715. end;
  716. procedure OutLn(s: String);
  717. begin
  718. OutStr(s + LineEnding);
  719. end;
  720. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  721. UseBytes: boolean = false);
  722. var
  723. res, NewStr: String;
  724. w: Cardinal;
  725. InString, NewInString: Boolean;
  726. begin
  727. if p = nil then begin
  728. res:= '''''';
  729. end
  730. else
  731. begin
  732. res := '';
  733. InString := False;
  734. while P < LastP do
  735. begin
  736. NewInString := InString;
  737. w := CharToOrdfunc(P);
  738. if w = ord('''') then
  739. begin //quote char
  740. if not InString then
  741. NewInString := True;
  742. NewStr := '''''';
  743. end
  744. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  745. begin //printable ascii or bytes
  746. if not InString then
  747. NewInString := True;
  748. NewStr := char(w);
  749. end
  750. else
  751. begin //ascii control chars, non ascii
  752. if InString then
  753. NewInString := False;
  754. NewStr := '#' + IntToStr(w);
  755. end;
  756. if NewInString <> InString then
  757. begin
  758. NewStr := '''' + NewStr;
  759. InString := NewInString;
  760. end;
  761. res := res + NewStr;
  762. end;
  763. if InString then
  764. res := res + '''';
  765. end;
  766. OutStr(res);
  767. end;
  768. procedure OutString(s: String);
  769. begin
  770. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  771. end;
  772. procedure OutWString(W: WideString);
  773. begin
  774. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  775. end;
  776. procedure OutUString(W: UnicodeString);
  777. begin
  778. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  779. end;
  780. procedure OutUtf8Str(s: String);
  781. begin
  782. if Encoding=oteLFM then
  783. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
  784. else
  785. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  786. end;
  787. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  788. begin
  789. Result:=Input.ReadWord;
  790. Result:=LEtoN(Result);
  791. end;
  792. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  793. begin
  794. Result:=Input.ReadDWord;
  795. Result:=LEtoN(Result);
  796. end;
  797. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  798. begin
  799. Input.ReadBuffer(Result,sizeof(Result));
  800. Result:=LEtoN(Result);
  801. end;
  802. {$ifndef FPUNONE}
  803. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  804. function ExtendedToDouble(e : pointer) : double;
  805. var mant : qword;
  806. exp : smallint;
  807. sign : boolean;
  808. d : qword;
  809. begin
  810. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  811. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  812. mant:=LEtoN(mant);
  813. exp:=LetoN(word(exp));
  814. sign:=(exp and $8000)<>0;
  815. if sign then exp:=exp and $7FFF;
  816. case exp of
  817. 0 : mant:=0; //if denormalized, value is too small for double,
  818. //so it's always zero
  819. $7FFF : exp:=2047 //either infinity or NaN
  820. else
  821. begin
  822. dec(exp,16383-1023);
  823. if (exp>=-51) and (exp<=0) then //can be denormalized
  824. begin
  825. mant:=mant shr (-exp);
  826. exp:=0;
  827. end
  828. else
  829. if (exp<-51) or (exp>2046) then //exponent too large.
  830. begin
  831. Result:=0;
  832. exit;
  833. end
  834. else //normalized value
  835. mant:=mant shl 1; //hide most significant bit
  836. end;
  837. end;
  838. d:=word(exp);
  839. d:=d shl 52;
  840. mant:=mant shr 12;
  841. d:=d or mant;
  842. if sign then d:=d or $8000000000000000;
  843. Result:=pdouble(@d)^;
  844. end;
  845. {$ENDIF}
  846. {$endif}
  847. function ReadInt(ValueType: TValueType): Int64;
  848. begin
  849. case ValueType of
  850. vaInt8: Result := ShortInt(Input.ReadByte);
  851. vaInt16: Result := SmallInt(ReadWord);
  852. vaInt32: Result := LongInt(ReadDWord);
  853. vaInt64: Result := Int64(ReadQWord);
  854. end;
  855. end;
  856. function ReadInt: Int64;
  857. begin
  858. Result := ReadInt(TValueType(Input.ReadByte));
  859. end;
  860. {$ifndef FPUNONE}
  861. function ReadExtended : extended;
  862. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  863. var ext : array[0..9] of byte;
  864. {$ENDIF}
  865. begin
  866. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  867. Input.ReadBuffer(ext[0],10);
  868. Result:=ExtendedToDouble(@(ext[0]));
  869. {$ELSE}
  870. Input.ReadBuffer(Result,sizeof(Result));
  871. {$ENDIF}
  872. end;
  873. {$endif}
  874. function ReadSStr: String;
  875. var
  876. len: Byte;
  877. begin
  878. len := Input.ReadByte;
  879. SetLength(Result, len);
  880. if (len > 0) then
  881. Input.ReadBuffer(Result[1], len);
  882. end;
  883. function ReadLStr: String;
  884. var
  885. len: DWord;
  886. begin
  887. len := ReadDWord;
  888. SetLength(Result, len);
  889. if (len > 0) then
  890. Input.ReadBuffer(Result[1], len);
  891. end;
  892. function ReadWStr: WideString;
  893. var
  894. len: DWord;
  895. {$IFDEF ENDIAN_BIG}
  896. i : integer;
  897. {$ENDIF}
  898. begin
  899. len := ReadDWord;
  900. SetLength(Result, len);
  901. if (len > 0) then
  902. begin
  903. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  904. {$IFDEF ENDIAN_BIG}
  905. for i:=1 to len do
  906. Result[i]:=widechar(SwapEndian(word(Result[i])));
  907. {$ENDIF}
  908. end;
  909. end;
  910. function ReadUStr: UnicodeString;
  911. var
  912. len: DWord;
  913. {$IFDEF ENDIAN_BIG}
  914. i : integer;
  915. {$ENDIF}
  916. begin
  917. len := ReadDWord;
  918. SetLength(Result, len);
  919. if (len > 0) then
  920. begin
  921. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  922. {$IFDEF ENDIAN_BIG}
  923. for i:=1 to len do
  924. Result[i]:=widechar(SwapEndian(word(Result[i])));
  925. {$ENDIF}
  926. end;
  927. end;
  928. procedure ReadPropList(indent: String);
  929. procedure ProcessValue(ValueType: TValueType; Indent: String);
  930. procedure ProcessBinary;
  931. var
  932. ToDo, DoNow, i: LongInt;
  933. lbuf: array[0..31] of Byte;
  934. s: String;
  935. begin
  936. ToDo := ReadDWord;
  937. OutLn('{');
  938. while ToDo > 0 do begin
  939. DoNow := ToDo;
  940. if DoNow > 32 then DoNow := 32;
  941. Dec(ToDo, DoNow);
  942. s := Indent + ' ';
  943. Input.ReadBuffer(lbuf, DoNow);
  944. for i := 0 to DoNow - 1 do
  945. s := s + IntToHex(lbuf[i], 2);
  946. OutLn(s);
  947. end;
  948. OutLn(indent + '}');
  949. end;
  950. var
  951. s: String;
  952. { len: LongInt; }
  953. IsFirst: Boolean;
  954. {$ifndef FPUNONE}
  955. ext: Extended;
  956. {$endif}
  957. begin
  958. case ValueType of
  959. vaList: begin
  960. OutStr('(');
  961. IsFirst := True;
  962. while True do begin
  963. ValueType := TValueType(Input.ReadByte);
  964. if ValueType = vaNull then break;
  965. if IsFirst then begin
  966. OutLn('');
  967. IsFirst := False;
  968. end;
  969. OutStr(Indent + ' ');
  970. ProcessValue(ValueType, Indent + ' ');
  971. end;
  972. OutLn(Indent + ')');
  973. end;
  974. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  975. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  976. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  977. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  978. {$ifndef FPUNONE}
  979. vaExtended: begin
  980. ext:=ReadExtended;
  981. Str(ext,S);// Do not use localized strings.
  982. OutLn(S);
  983. end;
  984. {$endif}
  985. vaString: begin
  986. OutString(ReadSStr);
  987. OutLn('');
  988. end;
  989. vaIdent: OutLn(ReadSStr);
  990. vaFalse: OutLn('False');
  991. vaTrue: OutLn('True');
  992. vaBinary: ProcessBinary;
  993. vaSet: begin
  994. OutStr('[');
  995. IsFirst := True;
  996. while True do begin
  997. s := ReadSStr;
  998. if Length(s) = 0 then break;
  999. if not IsFirst then OutStr(', ');
  1000. IsFirst := False;
  1001. OutStr(s);
  1002. end;
  1003. OutLn(']');
  1004. end;
  1005. vaLString:
  1006. begin
  1007. OutString(ReadLStr);
  1008. OutLn('');
  1009. end;
  1010. vaWString:
  1011. begin
  1012. OutWString(ReadWStr);
  1013. OutLn('');
  1014. end;
  1015. vaUString:
  1016. begin
  1017. OutWString(ReadWStr);
  1018. OutLn('');
  1019. end;
  1020. vaNil:
  1021. OutLn('nil');
  1022. vaCollection: begin
  1023. OutStr('<');
  1024. while Input.ReadByte <> 0 do begin
  1025. OutLn(Indent);
  1026. Input.Seek(-1, soFromCurrent);
  1027. OutStr(indent + ' item');
  1028. ValueType := TValueType(Input.ReadByte);
  1029. if ValueType <> vaList then
  1030. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1031. OutLn('');
  1032. ReadPropList(indent + ' ');
  1033. OutStr(indent + ' end');
  1034. end;
  1035. OutLn('>');
  1036. end;
  1037. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1038. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1039. vaDate: begin OutLn('!!Date!!'); exit end;}
  1040. vaUTF8String: begin
  1041. OutUtf8Str(ReadLStr);
  1042. OutLn('');
  1043. end;
  1044. else
  1045. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1046. end;
  1047. end;
  1048. begin
  1049. while Input.ReadByte <> 0 do begin
  1050. Input.Seek(-1, soFromCurrent);
  1051. OutStr(indent + ReadSStr + ' = ');
  1052. ProcessValue(TValueType(Input.ReadByte), Indent);
  1053. end;
  1054. end;
  1055. procedure ReadObject(indent: String);
  1056. var
  1057. b: Byte;
  1058. ObjClassName, ObjName: String;
  1059. ChildPos: LongInt;
  1060. begin
  1061. // Check for FilerFlags
  1062. b := Input.ReadByte;
  1063. if (b and $f0) = $f0 then begin
  1064. if (b and 2) <> 0 then ChildPos := ReadInt;
  1065. end else begin
  1066. b := 0;
  1067. Input.Seek(-1, soFromCurrent);
  1068. end;
  1069. ObjClassName := ReadSStr;
  1070. ObjName := ReadSStr;
  1071. OutStr(Indent);
  1072. if (b and 1) <> 0 then OutStr('inherited')
  1073. else
  1074. if (b and 4) <> 0 then OutStr('inline')
  1075. else OutStr('object');
  1076. OutStr(' ');
  1077. if ObjName <> '' then
  1078. OutStr(ObjName + ': ');
  1079. OutStr(ObjClassName);
  1080. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1081. OutLn('');
  1082. ReadPropList(indent + ' ');
  1083. while Input.ReadByte <> 0 do begin
  1084. Input.Seek(-1, soFromCurrent);
  1085. ReadObject(indent + ' ');
  1086. end;
  1087. OutLn(indent + 'end');
  1088. end;
  1089. type
  1090. PLongWord = ^LongWord;
  1091. const
  1092. signature: PChar = 'TPF0';
  1093. begin
  1094. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1095. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1096. ReadObject('');
  1097. end;
  1098. procedure ObjectBinaryToText(Input, Output: TStream);
  1099. begin
  1100. ObjectBinaryToText(Input,Output,oteDFM);
  1101. end;
  1102. procedure ObjectTextToBinary(Input, Output: TStream);
  1103. var
  1104. parser: TParser;
  1105. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1106. begin
  1107. w:=NtoLE(w);
  1108. Output.WriteWord(w);
  1109. end;
  1110. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1111. begin
  1112. lw:=NtoLE(lw);
  1113. Output.WriteDWord(lw);
  1114. end;
  1115. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1116. begin
  1117. qw:=NtoLE(qw);
  1118. Output.WriteBuffer(qw,sizeof(qword));
  1119. end;
  1120. {$ifndef FPUNONE}
  1121. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1122. procedure DoubleToExtended(d : double; e : pointer);
  1123. var mant : qword;
  1124. exp : smallint;
  1125. sign : boolean;
  1126. begin
  1127. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1128. exp :=(qword(d) shr 52) and $7FF;
  1129. sign:=(qword(d) and $8000000000000000)<>0;
  1130. case exp of
  1131. 0 : begin
  1132. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1133. begin
  1134. exp:=16383-1022;
  1135. while (mant and $8000000000000000)=0 do
  1136. begin
  1137. dec(exp);
  1138. mant:=mant shl 1;
  1139. end;
  1140. dec(exp); //don't shift, most significant bit is not hidden in extended
  1141. end;
  1142. end;
  1143. 2047 : exp:=$7FFF //either infinity or NaN
  1144. else
  1145. begin
  1146. inc(exp,16383-1023);
  1147. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1148. end;
  1149. end;
  1150. if sign then exp:=exp or $8000;
  1151. mant:=NtoLE(mant);
  1152. exp:=NtoLE(word(exp));
  1153. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1154. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1155. end;
  1156. {$ENDIF}
  1157. procedure WriteExtended(e : extended);
  1158. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1159. var ext : array[0..9] of byte;
  1160. {$ENDIF}
  1161. begin
  1162. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1163. DoubleToExtended(e,@(ext[0]));
  1164. Output.WriteBuffer(ext[0],10);
  1165. {$ELSE}
  1166. Output.WriteBuffer(e,sizeof(e));
  1167. {$ENDIF}
  1168. end;
  1169. {$endif}
  1170. procedure WriteString(s: String);
  1171. var size : byte;
  1172. begin
  1173. if length(s)>255 then size:=255
  1174. else size:=length(s);
  1175. Output.WriteByte(size);
  1176. if Length(s) > 0 then
  1177. Output.WriteBuffer(s[1], size);
  1178. end;
  1179. procedure WriteLString(Const s: String);
  1180. begin
  1181. WriteDWord(Length(s));
  1182. if Length(s) > 0 then
  1183. Output.WriteBuffer(s[1], Length(s));
  1184. end;
  1185. procedure WriteWString(Const s: WideString);
  1186. var len : longword;
  1187. {$IFDEF ENDIAN_BIG}
  1188. i : integer;
  1189. ws : widestring;
  1190. {$ENDIF}
  1191. begin
  1192. len:=Length(s);
  1193. WriteDWord(len);
  1194. if len > 0 then
  1195. begin
  1196. {$IFDEF ENDIAN_BIG}
  1197. setlength(ws,len);
  1198. for i:=1 to len do
  1199. ws[i]:=widechar(SwapEndian(word(s[i])));
  1200. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1201. {$ELSE}
  1202. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1203. {$ENDIF}
  1204. end;
  1205. end;
  1206. procedure WriteInteger(value: Int64);
  1207. begin
  1208. if (value >= -128) and (value <= 127) then begin
  1209. Output.WriteByte(Ord(vaInt8));
  1210. Output.WriteByte(byte(value));
  1211. end else if (value >= -32768) and (value <= 32767) then begin
  1212. Output.WriteByte(Ord(vaInt16));
  1213. WriteWord(word(value));
  1214. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1215. Output.WriteByte(Ord(vaInt32));
  1216. WriteDWord(longword(value));
  1217. end else begin
  1218. Output.WriteByte(ord(vaInt64));
  1219. WriteQWord(qword(value));
  1220. end;
  1221. end;
  1222. procedure ProcessWideString(const left : widestring);
  1223. var ws : widestring;
  1224. begin
  1225. ws:=left+parser.TokenWideString;
  1226. while parser.NextToken = '+' do
  1227. begin
  1228. parser.NextToken; // Get next string fragment
  1229. if not (parser.Token in [toString,toWString]) then
  1230. parser.CheckToken(toWString);
  1231. ws:=ws+parser.TokenWideString;
  1232. end;
  1233. Output.WriteByte(Ord(vaWstring));
  1234. WriteWString(ws);
  1235. end;
  1236. procedure ProcessProperty; forward;
  1237. procedure ProcessValue;
  1238. var
  1239. {$ifndef FPUNONE}
  1240. flt: Extended;
  1241. {$endif}
  1242. s: String;
  1243. stream: TMemoryStream;
  1244. begin
  1245. case parser.Token of
  1246. toInteger:
  1247. begin
  1248. WriteInteger(parser.TokenInt);
  1249. parser.NextToken;
  1250. end;
  1251. {$ifndef FPUNONE}
  1252. toFloat:
  1253. begin
  1254. Output.WriteByte(Ord(vaExtended));
  1255. flt := Parser.TokenFloat;
  1256. WriteExtended(flt);
  1257. parser.NextToken;
  1258. end;
  1259. {$endif}
  1260. toString:
  1261. begin
  1262. s := parser.TokenString;
  1263. while parser.NextToken = '+' do
  1264. begin
  1265. parser.NextToken; // Get next string fragment
  1266. case parser.Token of
  1267. toString : s:=s+parser.TokenString;
  1268. toWString : begin
  1269. ProcessWideString(s);
  1270. exit;
  1271. end
  1272. else parser.CheckToken(toString);
  1273. end;
  1274. end;
  1275. if (length(S)>255) then
  1276. begin
  1277. Output.WriteByte(Ord(vaLString));
  1278. WriteLString(S);
  1279. end
  1280. else
  1281. begin
  1282. Output.WriteByte(Ord(vaString));
  1283. WriteString(s);
  1284. end;
  1285. end;
  1286. toWString:
  1287. ProcessWideString('');
  1288. toSymbol:
  1289. begin
  1290. if CompareText(parser.TokenString, 'True') = 0 then
  1291. Output.WriteByte(Ord(vaTrue))
  1292. else if CompareText(parser.TokenString, 'False') = 0 then
  1293. Output.WriteByte(Ord(vaFalse))
  1294. else if CompareText(parser.TokenString, 'nil') = 0 then
  1295. Output.WriteByte(Ord(vaNil))
  1296. else
  1297. begin
  1298. Output.WriteByte(Ord(vaIdent));
  1299. WriteString(parser.TokenComponentIdent);
  1300. end;
  1301. Parser.NextToken;
  1302. end;
  1303. // Set
  1304. '[':
  1305. begin
  1306. parser.NextToken;
  1307. Output.WriteByte(Ord(vaSet));
  1308. if parser.Token <> ']' then
  1309. while True do
  1310. begin
  1311. parser.CheckToken(toSymbol);
  1312. WriteString(parser.TokenString);
  1313. parser.NextToken;
  1314. if parser.Token = ']' then
  1315. break;
  1316. parser.CheckToken(',');
  1317. parser.NextToken;
  1318. end;
  1319. Output.WriteByte(0);
  1320. parser.NextToken;
  1321. end;
  1322. // List
  1323. '(':
  1324. begin
  1325. parser.NextToken;
  1326. Output.WriteByte(Ord(vaList));
  1327. while parser.Token <> ')' do
  1328. ProcessValue;
  1329. Output.WriteByte(0);
  1330. parser.NextToken;
  1331. end;
  1332. // Collection
  1333. '<':
  1334. begin
  1335. parser.NextToken;
  1336. Output.WriteByte(Ord(vaCollection));
  1337. while parser.Token <> '>' do
  1338. begin
  1339. parser.CheckTokenSymbol('item');
  1340. parser.NextToken;
  1341. // ConvertOrder
  1342. Output.WriteByte(Ord(vaList));
  1343. while not parser.TokenSymbolIs('end') do
  1344. ProcessProperty;
  1345. parser.NextToken; // Skip 'end'
  1346. Output.WriteByte(0);
  1347. end;
  1348. Output.WriteByte(0);
  1349. parser.NextToken;
  1350. end;
  1351. // Binary data
  1352. '{':
  1353. begin
  1354. Output.WriteByte(Ord(vaBinary));
  1355. stream := TMemoryStream.Create;
  1356. try
  1357. parser.HexToBinary(stream);
  1358. WriteDWord(stream.Size);
  1359. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1360. finally
  1361. stream.Free;
  1362. end;
  1363. parser.NextToken;
  1364. end;
  1365. else
  1366. parser.Error(SInvalidProperty);
  1367. end;
  1368. end;
  1369. procedure ProcessProperty;
  1370. var
  1371. name: String;
  1372. begin
  1373. // Get name of property
  1374. parser.CheckToken(toSymbol);
  1375. name := parser.TokenString;
  1376. while True do begin
  1377. parser.NextToken;
  1378. if parser.Token <> '.' then break;
  1379. parser.NextToken;
  1380. parser.CheckToken(toSymbol);
  1381. name := name + '.' + parser.TokenString;
  1382. end;
  1383. WriteString(name);
  1384. parser.CheckToken('=');
  1385. parser.NextToken;
  1386. ProcessValue;
  1387. end;
  1388. procedure ProcessObject;
  1389. var
  1390. Flags: Byte;
  1391. ObjectName, ObjectType: String;
  1392. ChildPos: Integer;
  1393. begin
  1394. if parser.TokenSymbolIs('OBJECT') then
  1395. Flags :=0 { IsInherited := False }
  1396. else begin
  1397. if parser.TokenSymbolIs('INHERITED') then
  1398. Flags := 1 { IsInherited := True; }
  1399. else begin
  1400. parser.CheckTokenSymbol('INLINE');
  1401. Flags := 4;
  1402. end;
  1403. end;
  1404. parser.NextToken;
  1405. parser.CheckToken(toSymbol);
  1406. ObjectName := '';
  1407. ObjectType := parser.TokenString;
  1408. parser.NextToken;
  1409. if parser.Token = ':' then begin
  1410. parser.NextToken;
  1411. parser.CheckToken(toSymbol);
  1412. ObjectName := ObjectType;
  1413. ObjectType := parser.TokenString;
  1414. parser.NextToken;
  1415. if parser.Token = '[' then begin
  1416. parser.NextToken;
  1417. ChildPos := parser.TokenInt;
  1418. parser.NextToken;
  1419. parser.CheckToken(']');
  1420. parser.NextToken;
  1421. Flags := Flags or 2;
  1422. end;
  1423. end;
  1424. if Flags <> 0 then begin
  1425. Output.WriteByte($f0 or Flags);
  1426. if (Flags and 2) <> 0 then
  1427. WriteInteger(ChildPos);
  1428. end;
  1429. WriteString(ObjectType);
  1430. WriteString(ObjectName);
  1431. // Convert property list
  1432. while not (parser.TokenSymbolIs('END') or
  1433. parser.TokenSymbolIs('OBJECT') or
  1434. parser.TokenSymbolIs('INHERITED') or
  1435. parser.TokenSymbolIs('INLINE')) do
  1436. ProcessProperty;
  1437. Output.WriteByte(0); // Terminate property list
  1438. // Convert child objects
  1439. while not parser.TokenSymbolIs('END') do ProcessObject;
  1440. parser.NextToken; // Skip end token
  1441. Output.WriteByte(0); // Terminate property list
  1442. end;
  1443. const
  1444. signature: PChar = 'TPF0';
  1445. begin
  1446. parser := TParser.Create(Input);
  1447. try
  1448. Output.WriteBuffer(signature[0], 4);
  1449. ProcessObject;
  1450. finally
  1451. parser.Free;
  1452. end;
  1453. end;
  1454. procedure ObjectResourceToText(Input, Output: TStream);
  1455. begin
  1456. Input.ReadResHeader;
  1457. ObjectBinaryToText(Input, Output);
  1458. end;
  1459. procedure ObjectTextToResource(Input, Output: TStream);
  1460. var
  1461. StartPos, FixupInfo: LongInt;
  1462. parser: TParser;
  1463. name: String;
  1464. begin
  1465. // Get form type name
  1466. StartPos := Input.Position;
  1467. parser := TParser.Create(Input);
  1468. try
  1469. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1470. parser.NextToken;
  1471. parser.CheckToken(toSymbol);
  1472. parser.NextToken;
  1473. parser.CheckToken(':');
  1474. parser.NextToken;
  1475. parser.CheckToken(toSymbol);
  1476. name := parser.TokenString;
  1477. finally
  1478. parser.Free;
  1479. Input.Position := StartPos;
  1480. end;
  1481. name := UpperCase(name);
  1482. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1483. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1484. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1485. end;
  1486. { Utility routines }
  1487. function LineStart(Buffer, BufPos: PChar): PChar;
  1488. begin
  1489. Result := BufPos;
  1490. while Result > Buffer do begin
  1491. Dec(Result);
  1492. if Result[0] = #10 then break;
  1493. end;
  1494. end;
  1495. procedure CommonInit;
  1496. begin
  1497. InitCriticalSection(SynchronizeCritSect);
  1498. ExecuteEvent:=RtlEventCreate;
  1499. SynchronizeTimeoutEvent:=RtlEventCreate;
  1500. DoSynchronizeMethod:=false;
  1501. MainThreadID:=GetCurrentThreadID;
  1502. InitCriticalsection(ResolveSection);
  1503. InitHandlerList:=Nil;
  1504. FindGlobalComponentList:=nil;
  1505. IntConstList := TThreadList.Create;
  1506. ClassList := TThreadList.Create;
  1507. ClassAliasList := TStringList.Create;
  1508. { on unix this maps to a simple rw synchornizer }
  1509. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1510. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1511. end;
  1512. procedure CommonCleanup;
  1513. var
  1514. i: Integer;
  1515. begin
  1516. GlobalNameSpace.BeginWrite;
  1517. with IntConstList.LockList do
  1518. try
  1519. for i := 0 to Count - 1 do
  1520. TIntConst(Items[I]).Free;
  1521. finally
  1522. IntConstList.UnlockList;
  1523. end;
  1524. IntConstList.Free;
  1525. ClassList.Free;
  1526. ClassAliasList.Free;
  1527. RemoveFixupReferences(nil, '');
  1528. DoneCriticalsection(ResolveSection);
  1529. GlobalLists.Free;
  1530. ComponentPages.Free;
  1531. FreeAndNil(NeedResolving);
  1532. { GlobalNameSpace is an interface so this is enough }
  1533. GlobalNameSpace:=nil;
  1534. if (InitHandlerList<>Nil) then
  1535. for i := 0 to InitHandlerList.Count - 1 do
  1536. TInitHandler(InitHandlerList.Items[I]).Free;
  1537. InitHandlerList.Free;
  1538. InitHandlerList:=Nil;
  1539. FindGlobalComponentList.Free;
  1540. FindGlobalComponentList:=nil;
  1541. DoneCriticalSection(SynchronizeCritSect);
  1542. RtlEventDestroy(ExecuteEvent);
  1543. RtlEventDestroy(SynchronizeTimeoutEvent);
  1544. end;
  1545. { TFiler implementation }
  1546. {$i filer.inc}
  1547. { TReader implementation }
  1548. {$i reader.inc}
  1549. { TWriter implementations }
  1550. {$i writer.inc}
  1551. {$i twriter.inc}