classes.inc 42 KB

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