classes.inc 41 KB

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