classes.inc 42 KB

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