classes.inc 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748
  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);
  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. var
  716. res, NewStr: String;
  717. w: Cardinal;
  718. InString, NewInString: Boolean;
  719. begin
  720. if p = nil then begin
  721. res:= '''''';
  722. end
  723. else
  724. begin
  725. res := '';
  726. InString := False;
  727. while P < LastP do
  728. begin
  729. NewInString := InString;
  730. w := CharToOrdfunc(P);
  731. if w = ord('''') then
  732. begin //quote char
  733. if not InString then
  734. NewInString := True;
  735. NewStr := '''''';
  736. end
  737. else if (Ord(w) >= 32) and (Ord(w) < 127) then
  738. begin //printable ascii
  739. if not InString then
  740. NewInString := True;
  741. NewStr := char(w);
  742. end
  743. else
  744. begin //ascii control chars, non ascii
  745. if InString then
  746. NewInString := False;
  747. NewStr := '#' + IntToStr(w);
  748. end;
  749. if NewInString <> InString then
  750. begin
  751. NewStr := '''' + NewStr;
  752. InString := NewInString;
  753. end;
  754. res := res + NewStr;
  755. end;
  756. if InString then
  757. res := res + '''';
  758. end;
  759. OutStr(res);
  760. end;
  761. procedure OutString(s: String);
  762. begin
  763. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd);
  764. end;
  765. procedure OutWString(W: WideString);
  766. begin
  767. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  768. end;
  769. procedure OutUString(W: UnicodeString);
  770. begin
  771. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  772. end;
  773. procedure OutUtf8Str(s: String);
  774. begin
  775. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  776. end;
  777. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  778. begin
  779. Result:=Input.ReadWord;
  780. Result:=LEtoN(Result);
  781. end;
  782. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  783. begin
  784. Result:=Input.ReadDWord;
  785. Result:=LEtoN(Result);
  786. end;
  787. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  788. begin
  789. Input.ReadBuffer(Result,sizeof(Result));
  790. Result:=LEtoN(Result);
  791. end;
  792. {$ifndef FPUNONE}
  793. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  794. function ExtendedToDouble(e : pointer) : double;
  795. var mant : qword;
  796. exp : smallint;
  797. sign : boolean;
  798. d : qword;
  799. begin
  800. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  801. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  802. mant:=LEtoN(mant);
  803. exp:=LetoN(word(exp));
  804. sign:=(exp and $8000)<>0;
  805. if sign then exp:=exp and $7FFF;
  806. case exp of
  807. 0 : mant:=0; //if denormalized, value is too small for double,
  808. //so it's always zero
  809. $7FFF : exp:=2047 //either infinity or NaN
  810. else
  811. begin
  812. dec(exp,16383-1023);
  813. if (exp>=-51) and (exp<=0) then //can be denormalized
  814. begin
  815. mant:=mant shr (-exp);
  816. exp:=0;
  817. end
  818. else
  819. if (exp<-51) or (exp>2046) then //exponent too large.
  820. begin
  821. Result:=0;
  822. exit;
  823. end
  824. else //normalized value
  825. mant:=mant shl 1; //hide most significant bit
  826. end;
  827. end;
  828. d:=word(exp);
  829. d:=d shl 52;
  830. mant:=mant shr 12;
  831. d:=d or mant;
  832. if sign then d:=d or $8000000000000000;
  833. Result:=pdouble(@d)^;
  834. end;
  835. {$ENDIF}
  836. {$endif}
  837. function ReadInt(ValueType: TValueType): Int64;
  838. begin
  839. case ValueType of
  840. vaInt8: Result := ShortInt(Input.ReadByte);
  841. vaInt16: Result := SmallInt(ReadWord);
  842. vaInt32: Result := LongInt(ReadDWord);
  843. vaInt64: Result := Int64(ReadQWord);
  844. end;
  845. end;
  846. function ReadInt: Int64;
  847. begin
  848. Result := ReadInt(TValueType(Input.ReadByte));
  849. end;
  850. {$ifndef FPUNONE}
  851. function ReadExtended : extended;
  852. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  853. var ext : array[0..9] of byte;
  854. {$ENDIF}
  855. begin
  856. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  857. Input.ReadBuffer(ext[0],10);
  858. Result:=ExtendedToDouble(@(ext[0]));
  859. {$ELSE}
  860. Input.ReadBuffer(Result,sizeof(Result));
  861. {$ENDIF}
  862. end;
  863. {$endif}
  864. function ReadSStr: String;
  865. var
  866. len: Byte;
  867. begin
  868. len := Input.ReadByte;
  869. SetLength(Result, len);
  870. if (len > 0) then
  871. Input.ReadBuffer(Result[1], len);
  872. end;
  873. function ReadLStr: String;
  874. var
  875. len: DWord;
  876. begin
  877. len := ReadDWord;
  878. SetLength(Result, len);
  879. if (len > 0) then
  880. Input.ReadBuffer(Result[1], len);
  881. end;
  882. function ReadWStr: WideString;
  883. var
  884. len: DWord;
  885. {$IFDEF ENDIAN_BIG}
  886. i : integer;
  887. {$ENDIF}
  888. begin
  889. len := ReadDWord;
  890. SetLength(Result, len);
  891. if (len > 0) then
  892. begin
  893. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  894. {$IFDEF ENDIAN_BIG}
  895. for i:=1 to len do
  896. Result[i]:=widechar(SwapEndian(word(Result[i])));
  897. {$ENDIF}
  898. end;
  899. end;
  900. function ReadUStr: UnicodeString;
  901. var
  902. len: DWord;
  903. {$IFDEF ENDIAN_BIG}
  904. i : integer;
  905. {$ENDIF}
  906. begin
  907. len := ReadDWord;
  908. SetLength(Result, len);
  909. if (len > 0) then
  910. begin
  911. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  912. {$IFDEF ENDIAN_BIG}
  913. for i:=1 to len do
  914. Result[i]:=widechar(SwapEndian(word(Result[i])));
  915. {$ENDIF}
  916. end;
  917. end;
  918. procedure ReadPropList(indent: String);
  919. procedure ProcessValue(ValueType: TValueType; Indent: String);
  920. procedure ProcessBinary;
  921. var
  922. ToDo, DoNow, i: LongInt;
  923. lbuf: array[0..31] of Byte;
  924. s: String;
  925. begin
  926. ToDo := ReadDWord;
  927. OutLn('{');
  928. while ToDo > 0 do begin
  929. DoNow := ToDo;
  930. if DoNow > 32 then DoNow := 32;
  931. Dec(ToDo, DoNow);
  932. s := Indent + ' ';
  933. Input.ReadBuffer(lbuf, DoNow);
  934. for i := 0 to DoNow - 1 do
  935. s := s + IntToHex(lbuf[i], 2);
  936. OutLn(s);
  937. end;
  938. OutLn(indent + '}');
  939. end;
  940. var
  941. s: String;
  942. { len: LongInt; }
  943. IsFirst: Boolean;
  944. {$ifndef FPUNONE}
  945. ext: Extended;
  946. {$endif}
  947. begin
  948. case ValueType of
  949. vaList: begin
  950. OutStr('(');
  951. IsFirst := True;
  952. while True do begin
  953. ValueType := TValueType(Input.ReadByte);
  954. if ValueType = vaNull then break;
  955. if IsFirst then begin
  956. OutLn('');
  957. IsFirst := False;
  958. end;
  959. OutStr(Indent + ' ');
  960. ProcessValue(ValueType, Indent + ' ');
  961. end;
  962. OutLn(Indent + ')');
  963. end;
  964. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  965. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  966. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  967. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  968. {$ifndef FPUNONE}
  969. vaExtended: begin
  970. ext:=ReadExtended;
  971. Str(ext,S);// Do not use localized strings.
  972. OutLn(S);
  973. end;
  974. {$endif}
  975. vaString: begin
  976. OutString(ReadSStr);
  977. OutLn('');
  978. end;
  979. vaIdent: OutLn(ReadSStr);
  980. vaFalse: OutLn('False');
  981. vaTrue: OutLn('True');
  982. vaBinary: ProcessBinary;
  983. vaSet: begin
  984. OutStr('[');
  985. IsFirst := True;
  986. while True do begin
  987. s := ReadSStr;
  988. if Length(s) = 0 then break;
  989. if not IsFirst then OutStr(', ');
  990. IsFirst := False;
  991. OutStr(s);
  992. end;
  993. OutLn(']');
  994. end;
  995. vaLString:
  996. begin
  997. OutString(ReadLStr);
  998. OutLn('');
  999. end;
  1000. vaWString:
  1001. begin
  1002. OutWString(ReadWStr);
  1003. OutLn('');
  1004. end;
  1005. vaUString:
  1006. begin
  1007. OutWString(ReadWStr);
  1008. OutLn('');
  1009. end;
  1010. vaNil:
  1011. OutLn('nil');
  1012. vaCollection: begin
  1013. OutStr('<');
  1014. while Input.ReadByte <> 0 do begin
  1015. OutLn(Indent);
  1016. Input.Seek(-1, soFromCurrent);
  1017. OutStr(indent + ' item');
  1018. ValueType := TValueType(Input.ReadByte);
  1019. if ValueType <> vaList then
  1020. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1021. OutLn('');
  1022. ReadPropList(indent + ' ');
  1023. OutStr(indent + ' end');
  1024. end;
  1025. OutLn('>');
  1026. end;
  1027. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1028. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1029. vaDate: begin OutLn('!!Date!!'); exit end;}
  1030. vaUTF8String: begin
  1031. OutUtf8Str(ReadLStr);
  1032. OutLn('');
  1033. end;
  1034. else
  1035. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1036. end;
  1037. end;
  1038. begin
  1039. while Input.ReadByte <> 0 do begin
  1040. Input.Seek(-1, soFromCurrent);
  1041. OutStr(indent + ReadSStr + ' = ');
  1042. ProcessValue(TValueType(Input.ReadByte), Indent);
  1043. end;
  1044. end;
  1045. procedure ReadObject(indent: String);
  1046. var
  1047. b: Byte;
  1048. ObjClassName, ObjName: String;
  1049. ChildPos: LongInt;
  1050. begin
  1051. // Check for FilerFlags
  1052. b := Input.ReadByte;
  1053. if (b and $f0) = $f0 then begin
  1054. if (b and 2) <> 0 then ChildPos := ReadInt;
  1055. end else begin
  1056. b := 0;
  1057. Input.Seek(-1, soFromCurrent);
  1058. end;
  1059. ObjClassName := ReadSStr;
  1060. ObjName := ReadSStr;
  1061. OutStr(Indent);
  1062. if (b and 1) <> 0 then OutStr('inherited')
  1063. else
  1064. if (b and 4) <> 0 then OutStr('inline')
  1065. else OutStr('object');
  1066. OutStr(' ');
  1067. if ObjName <> '' then
  1068. OutStr(ObjName + ': ');
  1069. OutStr(ObjClassName);
  1070. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1071. OutLn('');
  1072. ReadPropList(indent + ' ');
  1073. while Input.ReadByte <> 0 do begin
  1074. Input.Seek(-1, soFromCurrent);
  1075. ReadObject(indent + ' ');
  1076. end;
  1077. OutLn(indent + 'end');
  1078. end;
  1079. type
  1080. PLongWord = ^LongWord;
  1081. const
  1082. signature: PChar = 'TPF0';
  1083. begin
  1084. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1085. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1086. ReadObject('');
  1087. end;
  1088. procedure ObjectTextToBinary(Input, Output: TStream);
  1089. var
  1090. parser: TParser;
  1091. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1092. begin
  1093. w:=NtoLE(w);
  1094. Output.WriteWord(w);
  1095. end;
  1096. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1097. begin
  1098. lw:=NtoLE(lw);
  1099. Output.WriteDWord(lw);
  1100. end;
  1101. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1102. begin
  1103. qw:=NtoLE(qw);
  1104. Output.WriteBuffer(qw,sizeof(qword));
  1105. end;
  1106. {$ifndef FPUNONE}
  1107. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1108. procedure DoubleToExtended(d : double; e : pointer);
  1109. var mant : qword;
  1110. exp : smallint;
  1111. sign : boolean;
  1112. begin
  1113. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1114. exp :=(qword(d) shr 52) and $7FF;
  1115. sign:=(qword(d) and $8000000000000000)<>0;
  1116. case exp of
  1117. 0 : begin
  1118. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1119. begin
  1120. exp:=16383-1022;
  1121. while (mant and $8000000000000000)=0 do
  1122. begin
  1123. dec(exp);
  1124. mant:=mant shl 1;
  1125. end;
  1126. dec(exp); //don't shift, most significant bit is not hidden in extended
  1127. end;
  1128. end;
  1129. 2047 : exp:=$7FFF //either infinity or NaN
  1130. else
  1131. begin
  1132. inc(exp,16383-1023);
  1133. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1134. end;
  1135. end;
  1136. if sign then exp:=exp or $8000;
  1137. mant:=NtoLE(mant);
  1138. exp:=NtoLE(word(exp));
  1139. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1140. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1141. end;
  1142. {$ENDIF}
  1143. procedure WriteExtended(e : extended);
  1144. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1145. var ext : array[0..9] of byte;
  1146. {$ENDIF}
  1147. begin
  1148. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1149. DoubleToExtended(e,@(ext[0]));
  1150. Output.WriteBuffer(ext[0],10);
  1151. {$ELSE}
  1152. Output.WriteBuffer(e,sizeof(e));
  1153. {$ENDIF}
  1154. end;
  1155. {$endif}
  1156. procedure WriteString(s: String);
  1157. var size : byte;
  1158. begin
  1159. if length(s)>255 then size:=255
  1160. else size:=length(s);
  1161. Output.WriteByte(size);
  1162. if Length(s) > 0 then
  1163. Output.WriteBuffer(s[1], size);
  1164. end;
  1165. procedure WriteLString(Const s: String);
  1166. begin
  1167. WriteDWord(Length(s));
  1168. if Length(s) > 0 then
  1169. Output.WriteBuffer(s[1], Length(s));
  1170. end;
  1171. procedure WriteWString(Const s: WideString);
  1172. var len : longword;
  1173. {$IFDEF ENDIAN_BIG}
  1174. i : integer;
  1175. ws : widestring;
  1176. {$ENDIF}
  1177. begin
  1178. len:=Length(s);
  1179. WriteDWord(len);
  1180. if len > 0 then
  1181. begin
  1182. {$IFDEF ENDIAN_BIG}
  1183. setlength(ws,len);
  1184. for i:=1 to len do
  1185. ws[i]:=widechar(SwapEndian(word(s[i])));
  1186. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1187. {$ELSE}
  1188. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1189. {$ENDIF}
  1190. end;
  1191. end;
  1192. procedure WriteInteger(value: Int64);
  1193. begin
  1194. if (value >= -128) and (value <= 127) then begin
  1195. Output.WriteByte(Ord(vaInt8));
  1196. Output.WriteByte(byte(value));
  1197. end else if (value >= -32768) and (value <= 32767) then begin
  1198. Output.WriteByte(Ord(vaInt16));
  1199. WriteWord(word(value));
  1200. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1201. Output.WriteByte(Ord(vaInt32));
  1202. WriteDWord(longword(value));
  1203. end else begin
  1204. Output.WriteByte(ord(vaInt64));
  1205. WriteQWord(qword(value));
  1206. end;
  1207. end;
  1208. procedure ProcessWideString(const left : widestring);
  1209. var ws : widestring;
  1210. begin
  1211. ws:=left+parser.TokenWideString;
  1212. while parser.NextToken = '+' do
  1213. begin
  1214. parser.NextToken; // Get next string fragment
  1215. if not (parser.Token in [toString,toWString]) then
  1216. parser.CheckToken(toWString);
  1217. ws:=ws+parser.TokenWideString;
  1218. end;
  1219. Output.WriteByte(Ord(vaWstring));
  1220. WriteWString(ws);
  1221. end;
  1222. procedure ProcessProperty; forward;
  1223. procedure ProcessValue;
  1224. var
  1225. {$ifndef FPUNONE}
  1226. flt: Extended;
  1227. {$endif}
  1228. s: String;
  1229. stream: TMemoryStream;
  1230. begin
  1231. case parser.Token of
  1232. toInteger:
  1233. begin
  1234. WriteInteger(parser.TokenInt);
  1235. parser.NextToken;
  1236. end;
  1237. {$ifndef FPUNONE}
  1238. toFloat:
  1239. begin
  1240. Output.WriteByte(Ord(vaExtended));
  1241. flt := Parser.TokenFloat;
  1242. WriteExtended(flt);
  1243. parser.NextToken;
  1244. end;
  1245. {$endif}
  1246. toString:
  1247. begin
  1248. s := parser.TokenString;
  1249. while parser.NextToken = '+' do
  1250. begin
  1251. parser.NextToken; // Get next string fragment
  1252. case parser.Token of
  1253. toString : s:=s+parser.TokenString;
  1254. toWString : begin
  1255. ProcessWideString(s);
  1256. exit;
  1257. end
  1258. else parser.CheckToken(toString);
  1259. end;
  1260. end;
  1261. if (length(S)>255) then
  1262. begin
  1263. Output.WriteByte(Ord(vaLString));
  1264. WriteLString(S);
  1265. end
  1266. else
  1267. begin
  1268. Output.WriteByte(Ord(vaString));
  1269. WriteString(s);
  1270. end;
  1271. end;
  1272. toWString:
  1273. ProcessWideString('');
  1274. toSymbol:
  1275. begin
  1276. if CompareText(parser.TokenString, 'True') = 0 then
  1277. Output.WriteByte(Ord(vaTrue))
  1278. else if CompareText(parser.TokenString, 'False') = 0 then
  1279. Output.WriteByte(Ord(vaFalse))
  1280. else if CompareText(parser.TokenString, 'nil') = 0 then
  1281. Output.WriteByte(Ord(vaNil))
  1282. else
  1283. begin
  1284. Output.WriteByte(Ord(vaIdent));
  1285. WriteString(parser.TokenComponentIdent);
  1286. end;
  1287. Parser.NextToken;
  1288. end;
  1289. // Set
  1290. '[':
  1291. begin
  1292. parser.NextToken;
  1293. Output.WriteByte(Ord(vaSet));
  1294. if parser.Token <> ']' then
  1295. while True do
  1296. begin
  1297. parser.CheckToken(toSymbol);
  1298. WriteString(parser.TokenString);
  1299. parser.NextToken;
  1300. if parser.Token = ']' then
  1301. break;
  1302. parser.CheckToken(',');
  1303. parser.NextToken;
  1304. end;
  1305. Output.WriteByte(0);
  1306. parser.NextToken;
  1307. end;
  1308. // List
  1309. '(':
  1310. begin
  1311. parser.NextToken;
  1312. Output.WriteByte(Ord(vaList));
  1313. while parser.Token <> ')' do
  1314. ProcessValue;
  1315. Output.WriteByte(0);
  1316. parser.NextToken;
  1317. end;
  1318. // Collection
  1319. '<':
  1320. begin
  1321. parser.NextToken;
  1322. Output.WriteByte(Ord(vaCollection));
  1323. while parser.Token <> '>' do
  1324. begin
  1325. parser.CheckTokenSymbol('item');
  1326. parser.NextToken;
  1327. // ConvertOrder
  1328. Output.WriteByte(Ord(vaList));
  1329. while not parser.TokenSymbolIs('end') do
  1330. ProcessProperty;
  1331. parser.NextToken; // Skip 'end'
  1332. Output.WriteByte(0);
  1333. end;
  1334. Output.WriteByte(0);
  1335. parser.NextToken;
  1336. end;
  1337. // Binary data
  1338. '{':
  1339. begin
  1340. Output.WriteByte(Ord(vaBinary));
  1341. stream := TMemoryStream.Create;
  1342. try
  1343. parser.HexToBinary(stream);
  1344. WriteDWord(stream.Size);
  1345. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1346. finally
  1347. stream.Free;
  1348. end;
  1349. parser.NextToken;
  1350. end;
  1351. else
  1352. parser.Error(SInvalidProperty);
  1353. end;
  1354. end;
  1355. procedure ProcessProperty;
  1356. var
  1357. name: String;
  1358. begin
  1359. // Get name of property
  1360. parser.CheckToken(toSymbol);
  1361. name := parser.TokenString;
  1362. while True do begin
  1363. parser.NextToken;
  1364. if parser.Token <> '.' then break;
  1365. parser.NextToken;
  1366. parser.CheckToken(toSymbol);
  1367. name := name + '.' + parser.TokenString;
  1368. end;
  1369. WriteString(name);
  1370. parser.CheckToken('=');
  1371. parser.NextToken;
  1372. ProcessValue;
  1373. end;
  1374. procedure ProcessObject;
  1375. var
  1376. Flags: Byte;
  1377. ObjectName, ObjectType: String;
  1378. ChildPos: Integer;
  1379. begin
  1380. if parser.TokenSymbolIs('OBJECT') then
  1381. Flags :=0 { IsInherited := False }
  1382. else begin
  1383. if parser.TokenSymbolIs('INHERITED') then
  1384. Flags := 1 { IsInherited := True; }
  1385. else begin
  1386. parser.CheckTokenSymbol('INLINE');
  1387. Flags := 4;
  1388. end;
  1389. end;
  1390. parser.NextToken;
  1391. parser.CheckToken(toSymbol);
  1392. ObjectName := '';
  1393. ObjectType := parser.TokenString;
  1394. parser.NextToken;
  1395. if parser.Token = ':' then begin
  1396. parser.NextToken;
  1397. parser.CheckToken(toSymbol);
  1398. ObjectName := ObjectType;
  1399. ObjectType := parser.TokenString;
  1400. parser.NextToken;
  1401. if parser.Token = '[' then begin
  1402. parser.NextToken;
  1403. ChildPos := parser.TokenInt;
  1404. parser.NextToken;
  1405. parser.CheckToken(']');
  1406. parser.NextToken;
  1407. Flags := Flags or 2;
  1408. end;
  1409. end;
  1410. if Flags <> 0 then begin
  1411. Output.WriteByte($f0 or Flags);
  1412. if (Flags and 2) <> 0 then
  1413. WriteInteger(ChildPos);
  1414. end;
  1415. WriteString(ObjectType);
  1416. WriteString(ObjectName);
  1417. // Convert property list
  1418. while not (parser.TokenSymbolIs('END') or
  1419. parser.TokenSymbolIs('OBJECT') or
  1420. parser.TokenSymbolIs('INHERITED') or
  1421. parser.TokenSymbolIs('INLINE')) do
  1422. ProcessProperty;
  1423. Output.WriteByte(0); // Terminate property list
  1424. // Convert child objects
  1425. while not parser.TokenSymbolIs('END') do ProcessObject;
  1426. parser.NextToken; // Skip end token
  1427. Output.WriteByte(0); // Terminate property list
  1428. end;
  1429. const
  1430. signature: PChar = 'TPF0';
  1431. begin
  1432. parser := TParser.Create(Input);
  1433. try
  1434. Output.WriteBuffer(signature[0], 4);
  1435. ProcessObject;
  1436. finally
  1437. parser.Free;
  1438. end;
  1439. end;
  1440. procedure ObjectResourceToText(Input, Output: TStream);
  1441. begin
  1442. Input.ReadResHeader;
  1443. ObjectBinaryToText(Input, Output);
  1444. end;
  1445. procedure ObjectTextToResource(Input, Output: TStream);
  1446. var
  1447. StartPos, FixupInfo: LongInt;
  1448. parser: TParser;
  1449. name: String;
  1450. begin
  1451. // Get form type name
  1452. StartPos := Input.Position;
  1453. parser := TParser.Create(Input);
  1454. try
  1455. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1456. parser.NextToken;
  1457. parser.CheckToken(toSymbol);
  1458. parser.NextToken;
  1459. parser.CheckToken(':');
  1460. parser.NextToken;
  1461. parser.CheckToken(toSymbol);
  1462. name := parser.TokenString;
  1463. finally
  1464. parser.Free;
  1465. Input.Position := StartPos;
  1466. end;
  1467. name := UpperCase(name);
  1468. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1469. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1470. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1471. end;
  1472. { Utility routines }
  1473. function LineStart(Buffer, BufPos: PChar): PChar;
  1474. begin
  1475. Result := BufPos;
  1476. while Result > Buffer do begin
  1477. Dec(Result);
  1478. if Result[0] = #10 then break;
  1479. end;
  1480. end;
  1481. procedure CommonInit;
  1482. begin
  1483. InitCriticalSection(SynchronizeCritSect);
  1484. ExecuteEvent:=RtlEventCreate;
  1485. SynchronizeTimeoutEvent:=RtlEventCreate;
  1486. DoSynchronizeMethod:=false;
  1487. MainThreadID:=GetCurrentThreadID;
  1488. InitCriticalsection(ResolveSection);
  1489. InitHandlerList:=Nil;
  1490. FindGlobalComponentList:=nil;
  1491. IntConstList := TThreadList.Create;
  1492. ClassList := TThreadList.Create;
  1493. ClassAliasList := TStringList.Create;
  1494. { on unix this maps to a simple rw synchornizer }
  1495. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1496. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1497. end;
  1498. procedure CommonCleanup;
  1499. var
  1500. i: Integer;
  1501. begin
  1502. GlobalNameSpace.BeginWrite;
  1503. with IntConstList.LockList do
  1504. try
  1505. for i := 0 to Count - 1 do
  1506. TIntConst(Items[I]).Free;
  1507. finally
  1508. IntConstList.UnlockList;
  1509. end;
  1510. IntConstList.Free;
  1511. ClassList.Free;
  1512. ClassAliasList.Free;
  1513. RemoveFixupReferences(nil, '');
  1514. DoneCriticalsection(ResolveSection);
  1515. GlobalLists.Free;
  1516. ComponentPages.Free;
  1517. FreeAndNil(NeedResolving);
  1518. { GlobalNameSpace is an interface so this is enough }
  1519. GlobalNameSpace:=nil;
  1520. if (InitHandlerList<>Nil) then
  1521. for i := 0 to InitHandlerList.Count - 1 do
  1522. TInitHandler(InitHandlerList.Items[I]).Free;
  1523. InitHandlerList.Free;
  1524. InitHandlerList:=Nil;
  1525. FindGlobalComponentList.Free;
  1526. FindGlobalComponentList:=nil;
  1527. DoneCriticalSection(SynchronizeCritSect);
  1528. RtlEventDestroy(ExecuteEvent);
  1529. RtlEventDestroy(SynchronizeTimeoutEvent);
  1530. end;
  1531. { TFiler implementation }
  1532. {$i filer.inc}
  1533. { TReader implementation }
  1534. {$i reader.inc}
  1535. { TWriter implementations }
  1536. {$i writer.inc}
  1537. {$i twriter.inc}