classes.inc 42 KB

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