classes.inc 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177
  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 executed by SychronizeInternal to wake main thread if it sleeps in
  48. CheckSynchronize }
  49. SynchronizeTimeoutEvent: PRtlEvent;
  50. { the head of the queue containing the entries to be Synchronized - Nil if the
  51. queue is empty }
  52. ThreadQueueHead: TThread.PThreadQueueEntry;
  53. { the tail of the queue containing the entries to be Synchronized - Nil if the
  54. queue is empty }
  55. ThreadQueueTail: TThread.PThreadQueueEntry;
  56. { used for serialized access to the queue }
  57. ThreadQueueLock: TRtlCriticalSection;
  58. { this list holds all instances of external threads that need to be freed at
  59. the end of the program }
  60. ExternalThreads: TThreadList;
  61. threadvar
  62. { the instance of the current thread; in case of an external thread this is
  63. Nil until TThread.GetCurrentThread was called once (the RTLs need to ensure
  64. that threadvars are initialized with 0!) }
  65. CurrentThreadVar: TThread;
  66. type
  67. { this type is used if a thread is created using
  68. TThread.CreateAnonymousThread }
  69. TAnonymousThread = class(TThread)
  70. private
  71. fProc: TProcedure;
  72. protected
  73. procedure Execute; override;
  74. public
  75. { as in TThread aProc needs to be changed to TProc once closures are
  76. supported }
  77. constructor Create(aProc: TProcedure);
  78. end;
  79. procedure TAnonymousThread.Execute;
  80. begin
  81. fProc();
  82. end;
  83. constructor TAnonymousThread.Create(aProc: TProcedure);
  84. begin
  85. { an anonymous thread is created suspended and with FreeOnTerminate set }
  86. inherited Create(True);
  87. FreeOnTerminate := True;
  88. fProc := aProc;
  89. end;
  90. type
  91. { this type is used by TThread.GetCurrentThread if the thread does not yet
  92. have a value in CurrentThreadVar (Note: the main thread is also created as
  93. a TExternalThread) }
  94. TExternalThread = class(TThread)
  95. protected
  96. { dummy method to remove the warning }
  97. procedure Execute; override;
  98. public
  99. constructor Create;
  100. end;
  101. procedure TExternalThread.Execute;
  102. begin
  103. { empty }
  104. end;
  105. constructor TExternalThread.Create;
  106. begin
  107. FExternalThread := True;
  108. { the parameter is unimportant if FExternalThread is True }
  109. inherited Create(False);
  110. end;
  111. function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
  112. var
  113. FreeThread: Boolean;
  114. Thread: TThread absolute ThreadObjPtr;
  115. begin
  116. { if Suspend checks FSuspended before doing anything, make sure it }
  117. { knows we're currently not suspended (this flag may have been set }
  118. { to true if CreateSuspended was true) }
  119. // Thread.FSuspended:=false;
  120. // wait until AfterConstruction has been called, so we cannot
  121. // free ourselves before TThread.Create has finished
  122. // (since that one may check our VTM in case of $R+, and
  123. // will call the AfterConstruction method in all cases)
  124. // Thread.Suspend;
  125. try
  126. { The thread may be already terminated at this point, e.g. if it was intially
  127. suspended, or if it wasn't ever scheduled for execution for whatever reason.
  128. So bypass user code if terminated. }
  129. if not Thread.Terminated then begin
  130. CurrentThreadVar := Thread;
  131. Thread.Execute;
  132. end;
  133. except
  134. Thread.FFatalException := TObject(AcquireExceptionObject);
  135. end;
  136. FreeThread := Thread.FFreeOnTerminate;
  137. Result := Thread.FReturnValue;
  138. Thread.FFinished := True;
  139. Thread.DoTerminate;
  140. if FreeThread then
  141. Thread.Free;
  142. EndThread(Result);
  143. end;
  144. { system-dependent code }
  145. {$i tthread.inc}
  146. constructor TThread.Create(CreateSuspended: Boolean;
  147. const StackSize: SizeUInt);
  148. begin
  149. inherited Create;
  150. if FExternalThread then
  151. FThreadID := GetCurrentThreadID
  152. else
  153. SysCreate(CreateSuspended, StackSize);
  154. end;
  155. destructor TThread.Destroy;
  156. begin
  157. if not FExternalThread then begin
  158. SysDestroy;
  159. if FHandle <> TThreadID(0) then
  160. CloseThread(FHandle);
  161. end;
  162. RemoveQueuedEvents(Self);
  163. DoneSynchronizeEvent;
  164. { set CurrentThreadVar to Nil? }
  165. inherited Destroy;
  166. end;
  167. procedure TThread.Start;
  168. begin
  169. { suspend/resume are now deprecated in Delphi (they also don't work
  170. on most platforms in FPC), so a different method was required
  171. to start a thread if it's create with fSuspended=true -> that's
  172. what this method is for. }
  173. Resume;
  174. end;
  175. function TThread.GetSuspended: Boolean;
  176. begin
  177. GetSuspended:=FSuspended;
  178. end;
  179. procedure TThread.AfterConstruction;
  180. begin
  181. inherited AfterConstruction;
  182. // enable for all platforms once http://bugs.freepascal.org/view.php?id=16884
  183. // is fixed for all platforms (in case the fix for non-unix platforms also
  184. // requires this field at least)
  185. {$if defined(unix) or defined(windows)}
  186. if not FExternalThread and not FInitialSuspended then
  187. Resume;
  188. {$endif}
  189. end;
  190. procedure ExecuteThreadQueueEntry(aEntry: TThread.PThreadQueueEntry);
  191. begin
  192. if Assigned(aEntry^.Method) then
  193. aEntry^.Method()
  194. // enable once closures are supported
  195. {else
  196. aEntry^.ThreadProc();}
  197. end;
  198. procedure ThreadQueueAppend(aEntry: TThread.PThreadQueueEntry);
  199. begin
  200. { do we really need a synchronized call? }
  201. if GetCurrentThreadID = MainThreadID then begin
  202. ExecuteThreadQueueEntry(aEntry);
  203. if not Assigned(aEntry^.SyncEvent) then
  204. Dispose(aEntry);
  205. end else begin
  206. System.EnterCriticalSection(ThreadQueueLock);
  207. try
  208. { add the entry to the thread queue }
  209. if Assigned(ThreadQueueTail) then begin
  210. ThreadQueueTail^.Next := aEntry;
  211. end else
  212. ThreadQueueHead := aEntry;
  213. ThreadQueueTail := aEntry;
  214. finally
  215. System.LeaveCriticalSection(ThreadQueueLock);
  216. end;
  217. { ensure that the main thread knows that something awaits }
  218. RtlEventSetEvent(SynchronizeTimeoutEvent);
  219. if assigned(WakeMainThread) then
  220. WakeMainThread(aEntry^.Thread);
  221. { is this a Synchronize or Queue entry? }
  222. if Assigned(aEntry^.SyncEvent) then begin
  223. RtlEventWaitFor(aEntry^.SyncEvent);
  224. if Assigned(aEntry^.Exception) then
  225. raise aEntry^.Exception;
  226. end;
  227. end;
  228. end;
  229. procedure TThread.InitSynchronizeEvent;
  230. begin
  231. if Assigned(FSynchronizeEntry) then
  232. Exit;
  233. New(FSynchronizeEntry);
  234. FillChar(FSynchronizeEntry^, SizeOf(TThreadQueueEntry), 0);
  235. FSynchronizeEntry^.Thread := Self;
  236. FSynchronizeEntry^.SyncEvent := RtlEventCreate;
  237. end;
  238. procedure TThread.DoneSynchronizeEvent;
  239. begin
  240. if not Assigned(FSynchronizeEntry) then
  241. Exit;
  242. RtlEventDestroy(FSynchronizeEntry^.SyncEvent);
  243. Dispose(FSynchronizeEntry);
  244. FSynchronizeEntry := Nil;
  245. end;
  246. class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
  247. begin
  248. { ensure that we have a TThread instance }
  249. if not Assigned(AThread) then
  250. AThread := CurrentThread;
  251. { the Synchronize event is instantiated on demand }
  252. AThread.InitSynchronizeEvent;
  253. AThread.FSynchronizeEntry^.Exception := Nil;
  254. AThread.FSynchronizeEntry^.Method := AMethod;
  255. ThreadQueueAppend(AThread.FSynchronizeEntry);
  256. AThread.FSynchronizeEntry^.Method := Nil;
  257. AThread.FSynchronizeEntry^.Next := Nil;
  258. end;
  259. procedure TThread.Synchronize(AMethod: TThreadMethod);
  260. begin
  261. TThread.Synchronize(self,AMethod);
  262. end;
  263. function CheckSynchronize(timeout : longint=0) : boolean;
  264. { assumes being called from GUI thread }
  265. var
  266. exceptobj: Exception;
  267. tmpentry: TThread.PThreadQueueEntry;
  268. begin
  269. result:=false;
  270. { first sanity check }
  271. if Not IsMultiThread then
  272. Exit
  273. { second sanity check }
  274. else if GetCurrentThreadID<>MainThreadID then
  275. raise EThread.CreateFmt(SCheckSynchronizeError,[GetCurrentThreadID])
  276. else
  277. begin
  278. if timeout>0 then
  279. begin
  280. RtlEventWaitFor(SynchronizeTimeoutEvent,timeout);
  281. end
  282. else
  283. RtlEventResetEvent(SynchronizeTimeoutEvent);
  284. System.EnterCriticalSection(ThreadQueueLock);
  285. try
  286. { Note: we don't need to pay attention to recursive calls to
  287. Synchronize as those calls will be executed in the context of
  288. the GUI thread and thus will be executed immediatly instead of
  289. queuing them }
  290. while Assigned(ThreadQueueHead) do begin
  291. { step 1: update the list }
  292. tmpentry := ThreadQueueHead;
  293. ThreadQueueHead := ThreadQueueHead^.Next;
  294. if not Assigned(ThreadQueueHead) then
  295. ThreadQueueTail := Nil;
  296. { step 2: execute the method }
  297. exceptobj := Nil;
  298. try
  299. ExecuteThreadQueueEntry(tmpentry);
  300. except
  301. exceptobj := Exception(AcquireExceptionObject);
  302. end;
  303. { step 3: error handling and cleanup }
  304. if Assigned(tmpentry^.SyncEvent) then begin
  305. { for Synchronize entries we pass back the Exception and trigger
  306. the event that Synchronize waits in }
  307. tmpentry^.Exception := exceptobj;
  308. RtlEventSetEvent(tmpentry^.SyncEvent)
  309. end else begin
  310. { for Queue entries we dispose the entry and raise the exception }
  311. Dispose(tmpentry);
  312. if Assigned(exceptobj) then
  313. raise exceptobj;
  314. end;
  315. end;
  316. finally
  317. System.LeaveCriticalSection(ThreadQueueLock);
  318. end;
  319. end;
  320. end;
  321. class function TThread.GetCurrentThread: TThread;
  322. begin
  323. { if this is the first time GetCurrentThread is called for an external thread
  324. we need to create a corresponding TExternalThread instance }
  325. Result := CurrentThreadVar;
  326. if not Assigned(Result) then begin
  327. Result := TExternalThread.Create;
  328. CurrentThreadVar := Result;
  329. end;
  330. end;
  331. class function TThread.GetIsSingleProcessor: Boolean;
  332. begin
  333. Result := FProcessorCount <= 1;
  334. end;
  335. procedure TThread.Queue(aMethod: TThreadMethod);
  336. begin
  337. Queue(Self, aMethod);
  338. end;
  339. class procedure TThread.Queue(aThread: TThread; aMethod: TThreadMethod); static;
  340. var
  341. queueentry: PThreadQueueEntry;
  342. begin
  343. { ensure that we have a valid TThread instance }
  344. if not Assigned(aThread) then
  345. aThread := CurrentThread;
  346. New(queueentry);
  347. FillChar(queueentry^, SizeOf(TThreadQueueEntry), 0);
  348. queueentry^.Thread := aThread;
  349. queueentry^.Method := aMethod;
  350. { the queueentry is freed by CheckSynchronize (or by RemoveQueuedEvents) }
  351. ThreadQueueAppend(queueentry);
  352. end;
  353. class procedure TThread.RemoveQueuedEvents(aThread: TThread; aMethod: TThreadMethod);
  354. var
  355. entry, tmpentry, lastentry: PThreadQueueEntry;
  356. begin
  357. { anything to do at all? }
  358. if not Assigned(aThread) or not Assigned(aMethod) then
  359. Exit;
  360. System.EnterCriticalSection(ThreadQueueLock);
  361. try
  362. lastentry := Nil;
  363. entry := ThreadQueueHead;
  364. while Assigned(entry) do begin
  365. { first check for the thread }
  366. if Assigned(aThread) and (entry^.Thread <> aThread) then begin
  367. lastentry := entry;
  368. entry := entry^.Next;
  369. Continue;
  370. end;
  371. { then check for the method }
  372. if entry^.Method <> aMethod then begin
  373. lastentry := entry;
  374. entry := entry^.Next;
  375. Continue;
  376. end;
  377. { skip entries added by Synchronize }
  378. if Assigned(entry^.SyncEvent) then begin
  379. lastentry := entry;
  380. entry := entry^.Next;
  381. Continue;
  382. end;
  383. { ok, we need to remove this entry }
  384. tmpentry := entry;
  385. if Assigned(lastentry) then
  386. lastentry^.Next := entry^.Next;
  387. entry := entry^.Next;
  388. if ThreadQueueHead = tmpentry then
  389. ThreadQueueHead := entry;
  390. if ThreadQueueTail = tmpentry then
  391. ThreadQueueTail := lastentry;
  392. { only dispose events added by Queue }
  393. if not Assigned(tmpentry^.SyncEvent) then
  394. Dispose(tmpentry);
  395. end;
  396. finally
  397. System.LeaveCriticalSection(ThreadQueueLock);
  398. end;
  399. end;
  400. class procedure TThread.RemoveQueuedEvents(aMethod: TThreadMethod);
  401. begin
  402. RemoveQueuedEvents(Nil, aMethod);
  403. end;
  404. class procedure TThread.RemoveQueuedEvents(aThread: TThread);
  405. begin
  406. RemoveQueuedEvents(aThread, Nil);
  407. end;
  408. class function TThread.CheckTerminated: Boolean;
  409. begin
  410. { this method only works with threads created by TThread, so we can make a
  411. shortcut here }
  412. if not Assigned(CurrentThreadVar) then
  413. raise EThreadExternalException.Create(SThreadExternal);
  414. Result := CurrentThreadVar.FTerminated;
  415. end;
  416. class procedure TThread.SetReturnValue(aValue: Integer);
  417. begin
  418. { this method only works with threads created by TThread, so we can make a
  419. shortcut here }
  420. if not Assigned(CurrentThreadVar) then
  421. raise EThreadExternalException.Create(SThreadExternal);
  422. CurrentThreadVar.FReturnValue := aValue;
  423. end;
  424. class function TThread.CreateAnonymousThread(aProc: TProcedure): TThread;
  425. begin
  426. if not Assigned(aProc) then
  427. raise Exception.Create(SNoProcGiven);
  428. Result := TAnonymousThread.Create(aProc);
  429. end;
  430. {$ifdef THREADNAME_IS_ANSISTRING}
  431. { the platform implements the AnsiString variant and the UnicodeString variant
  432. simply calls the AnsiString variant }
  433. class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
  434. begin
  435. NameThreadForDebugging(AnsiString(aThreadName), aThreadID);
  436. end;
  437. {$ifndef HAS_TTHREAD_NAMETHREADFORDEBUGGING}
  438. class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
  439. begin
  440. { empty }
  441. end;
  442. {$endif}
  443. {$else}
  444. {$ifndef HAS_TTHREAD_NAMETHREADFORDEBUGGING}
  445. { the platform implements the UnicodeString variant and the AnsiString variant
  446. simply calls the UnicodeString variant }
  447. class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
  448. begin
  449. { empty }
  450. end;
  451. {$endif}
  452. class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
  453. begin
  454. NameThreadForDebugging(UnicodeString(aThreadName), aThreadID);
  455. end;
  456. {$endif}
  457. class procedure TThread.Yield;
  458. begin
  459. ThreadSwitch;
  460. end;
  461. class procedure TThread.Sleep(aMilliseconds: Cardinal);
  462. begin
  463. SysUtils.Sleep(aMilliseconds);
  464. end;
  465. class procedure TThread.SpinWait(aIterations: LongWord);
  466. begin
  467. { yes, it's just a simple busy wait to burn some cpu cycles... and as the job
  468. of this loop is to burn CPU cycles we switch off any optimizations that
  469. could interfere with this (e.g. loop unrolling) }
  470. {$PUSH}
  471. {$OPTIMIZATION OFF}
  472. while aIterations > 0 do
  473. Dec(aIterations);
  474. {$POP}
  475. end;
  476. {$ifndef HAS_TTHREAD_GETSYSTEMTIMES}
  477. class procedure TThread.GetSystemTimes(out aSystemTimes: TSystemTimes);
  478. begin
  479. { by default we just return a zeroed out record }
  480. FillChar(aSystemTimes, SizeOf(aSystemTimes), 0);
  481. end;
  482. {$endif}
  483. class function TThread.GetTickCount: LongWord;
  484. begin
  485. Result := SysUtils.GetTickCount;
  486. end;
  487. class function TThread.GetTickCount64: QWord;
  488. begin
  489. Result := SysUtils.GetTickCount64;
  490. end;
  491. { TPersistent implementation }
  492. {$i persist.inc }
  493. {$i sllist.inc}
  494. {$i resref.inc}
  495. { TComponent implementation }
  496. {$i compon.inc}
  497. { TBasicAction implementation }
  498. {$i action.inc}
  499. { TDataModule implementation }
  500. {$i dm.inc}
  501. { Class and component registration routines }
  502. {$I cregist.inc}
  503. { Interface related stuff }
  504. {$I intf.inc}
  505. {**********************************************************************
  506. * Miscellaneous procedures and functions *
  507. **********************************************************************}
  508. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings): Integer;
  509. var
  510. b, c : pchar;
  511. procedure SkipWhitespace;
  512. begin
  513. while (c^ in Whitespace) do
  514. inc (c);
  515. end;
  516. procedure AddString;
  517. var
  518. l : integer;
  519. s : string;
  520. begin
  521. l := c-b;
  522. if l > 0 then
  523. begin
  524. if assigned(Strings) then
  525. begin
  526. setlength(s, l);
  527. move (b^, s[1],l);
  528. Strings.Add (s);
  529. end;
  530. inc (result);
  531. end;
  532. end;
  533. var
  534. quoted : char;
  535. begin
  536. result := 0;
  537. c := Content;
  538. Quoted := #0;
  539. Separators := Separators + [#13, #10] - ['''','"'];
  540. SkipWhitespace;
  541. b := c;
  542. while (c^ <> #0) do
  543. begin
  544. if (c^ = Quoted) then
  545. begin
  546. if ((c+1)^ = Quoted) then
  547. inc (c)
  548. else
  549. Quoted := #0
  550. end
  551. else if (Quoted = #0) and (c^ in ['''','"']) then
  552. Quoted := c^;
  553. if (Quoted = #0) and (c^ in Separators) then
  554. begin
  555. AddString;
  556. inc (c);
  557. SkipWhitespace;
  558. b := c;
  559. end
  560. else
  561. inc (c);
  562. end;
  563. if (c <> b) then
  564. AddString;
  565. end;
  566. { Point and rectangle constructors }
  567. function Point(AX, AY: Integer): TPoint;
  568. begin
  569. with Result do
  570. begin
  571. X := AX;
  572. Y := AY;
  573. end;
  574. end;
  575. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  576. begin
  577. with Result do
  578. begin
  579. X := AX;
  580. Y := AY;
  581. end;
  582. end;
  583. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  584. begin
  585. with Result do
  586. begin
  587. Left := ALeft;
  588. Top := ATop;
  589. Right := ARight;
  590. Bottom := ABottom;
  591. end;
  592. end;
  593. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  594. begin
  595. with Result do
  596. begin
  597. Left := ALeft;
  598. Top := ATop;
  599. Right := ALeft + AWidth;
  600. Bottom := ATop + AHeight;
  601. end;
  602. end;
  603. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  604. begin
  605. { lazy, but should work }
  606. result:=QWord(P1)=QWord(P2);
  607. end;
  608. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  609. begin
  610. { lazy, but should work }
  611. result:=DWord(P1)=DWord(P2);
  612. end;
  613. function InvalidPoint(X, Y: Integer): Boolean;
  614. begin
  615. result:=(X=-1) and (Y=-1);
  616. end;
  617. function InvalidPoint(const At: TPoint): Boolean;
  618. begin
  619. result:=(At.x=-1) and (At.y=-1);
  620. end;
  621. function InvalidPoint(const At: TSmallPoint): Boolean;
  622. begin
  623. result:=(At.x=-1) and (At.y=-1);
  624. end;
  625. { Object filing routines }
  626. var
  627. IntConstList: TThreadList;
  628. type
  629. TIntConst = class
  630. IntegerType: PTypeInfo; // The integer type RTTI pointer
  631. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  632. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  633. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  634. AIntToIdent: TIntToIdent);
  635. end;
  636. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  637. AIntToIdent: TIntToIdent);
  638. begin
  639. IntegerType := AIntegerType;
  640. IdentToIntFn := AIdentToInt;
  641. IntToIdentFn := AIntToIdent;
  642. end;
  643. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  644. IntToIdentFn: TIntToIdent);
  645. begin
  646. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  647. end;
  648. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  649. var
  650. i: Integer;
  651. begin
  652. with IntConstList.LockList do
  653. try
  654. for i := 0 to Count - 1 do
  655. if TIntConst(Items[i]).IntegerType = AIntegerType then
  656. exit(TIntConst(Items[i]).IntToIdentFn);
  657. Result := nil;
  658. finally
  659. IntConstList.UnlockList;
  660. end;
  661. end;
  662. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  663. var
  664. i: Integer;
  665. begin
  666. with IntConstList.LockList do
  667. try
  668. for i := 0 to Count - 1 do
  669. with TIntConst(Items[I]) do
  670. if TIntConst(Items[I]).IntegerType = AIntegerType then
  671. exit(IdentToIntFn);
  672. Result := nil;
  673. finally
  674. IntConstList.UnlockList;
  675. end;
  676. end;
  677. function IdentToInt(const Ident: String; var Int: LongInt;
  678. const Map: array of TIdentMapEntry): Boolean;
  679. var
  680. i: Integer;
  681. begin
  682. for i := Low(Map) to High(Map) do
  683. if CompareText(Map[i].Name, Ident) = 0 then
  684. begin
  685. Int := Map[i].Value;
  686. exit(True);
  687. end;
  688. Result := False;
  689. end;
  690. function IntToIdent(Int: LongInt; var Ident: String;
  691. const Map: array of TIdentMapEntry): Boolean;
  692. var
  693. i: Integer;
  694. begin
  695. for i := Low(Map) to High(Map) do
  696. if Map[i].Value = Int then
  697. begin
  698. Ident := Map[i].Name;
  699. exit(True);
  700. end;
  701. Result := False;
  702. end;
  703. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  704. var
  705. i : Integer;
  706. begin
  707. with IntConstList.LockList do
  708. try
  709. for i := 0 to Count - 1 do
  710. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  711. Exit(True);
  712. Result := false;
  713. finally
  714. IntConstList.UnlockList;
  715. end;
  716. end;
  717. { TPropFixup }
  718. // Tainted. TPropFixup is being removed.
  719. Type
  720. TInitHandler = Class(TObject)
  721. AHandler : TInitComponentHandler;
  722. AClass : TComponentClass;
  723. end;
  724. {$ifndef i8086}
  725. type
  726. TCodePtrList = TList;
  727. {$endif i8086}
  728. Var
  729. InitHandlerList : TList;
  730. FindGlobalComponentList : TCodePtrList;
  731. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  732. begin
  733. if not(assigned(FindGlobalComponentList)) then
  734. FindGlobalComponentList:=TCodePtrList.Create;
  735. if FindGlobalComponentList.IndexOf(CodePointer(AFindGlobalComponent))<0 then
  736. FindGlobalComponentList.Add(CodePointer(AFindGlobalComponent));
  737. end;
  738. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  739. begin
  740. if assigned(FindGlobalComponentList) then
  741. FindGlobalComponentList.Remove(CodePointer(AFindGlobalComponent));
  742. end;
  743. function FindGlobalComponent(const Name: string): TComponent;
  744. var
  745. i : sizeint;
  746. begin
  747. FindGlobalComponent:=nil;
  748. if assigned(FindGlobalComponentList) then
  749. begin
  750. for i:=FindGlobalComponentList.Count-1 downto 0 do
  751. begin
  752. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  753. if assigned(FindGlobalComponent) then
  754. break;
  755. end;
  756. end;
  757. end;
  758. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  759. Var
  760. I : Integer;
  761. H: TInitHandler;
  762. begin
  763. If (InitHandlerList=Nil) then
  764. InitHandlerList:=TList.Create;
  765. H:=TInitHandler.Create;
  766. H.Aclass:=ComponentClass;
  767. H.AHandler:=Handler;
  768. try
  769. With InitHandlerList do
  770. begin
  771. I:=0;
  772. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  773. Inc(I);
  774. { override? }
  775. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  776. begin
  777. TInitHandler(Items[I]).AHandler:=Handler;
  778. H.Free;
  779. end
  780. else
  781. InitHandlerList.Insert(I,H);
  782. end;
  783. except
  784. H.Free;
  785. raise;
  786. end;
  787. end;
  788. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  789. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  790. var
  791. ResStream : TResourceStream;
  792. begin
  793. result:=true;
  794. if Inst=0 then
  795. Inst:=HInstance;
  796. try
  797. ResStream:=TResourceStream.Create(Inst,res,RT_RCDATA);
  798. try
  799. Component:=ResStream.ReadComponent(Component);
  800. finally
  801. ResStream.Free;
  802. end;
  803. except
  804. on EResNotFound do
  805. result:=false;
  806. end;
  807. end;
  808. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  809. function doinit(_class : TClass) : boolean;
  810. begin
  811. result:=false;
  812. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  813. exit;
  814. result:=doinit(_class.ClassParent);
  815. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  816. end;
  817. begin
  818. GlobalNameSpace.BeginWrite;
  819. try
  820. result:=doinit(Instance.ClassType);
  821. finally
  822. GlobalNameSpace.EndWrite;
  823. end;
  824. end;
  825. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  826. Var
  827. I : Integer;
  828. begin
  829. I:=0;
  830. if not Assigned(InitHandlerList) then begin
  831. Result := True;
  832. Exit;
  833. end;
  834. Result:=False;
  835. With InitHandlerList do
  836. begin
  837. I:=0;
  838. // Instance is the normally the lowest one, so that one should be used when searching.
  839. While Not result and (I<Count) do
  840. begin
  841. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  842. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  843. Inc(I);
  844. end;
  845. end;
  846. end;
  847. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  848. begin
  849. { !!!: Too Win32-specific }
  850. InitComponentRes := False;
  851. end;
  852. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  853. begin
  854. { !!!: Too Win32-specific }
  855. ReadComponentRes := nil;
  856. end;
  857. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  858. begin
  859. { !!!: Too Win32-specific in VCL }
  860. ReadComponentResEx := nil;
  861. end;
  862. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  863. var
  864. FileStream: TStream;
  865. begin
  866. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  867. try
  868. Result := FileStream.ReadComponentRes(Instance);
  869. finally
  870. FileStream.Free;
  871. end;
  872. end;
  873. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  874. var
  875. FileStream: TStream;
  876. begin
  877. FileStream := TFileStream.Create(FileName, fmCreate);
  878. try
  879. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  880. finally
  881. FileStream.Free;
  882. end;
  883. end;
  884. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  885. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  886. Var
  887. P : Integer;
  888. CM : Boolean;
  889. begin
  890. P:=Pos('.',APath);
  891. CM:=False;
  892. If (P=0) then
  893. begin
  894. If CStyle then
  895. begin
  896. P:=Pos('->',APath);
  897. CM:=P<>0;
  898. end;
  899. If (P=0) Then
  900. P:=Length(APath)+1;
  901. end;
  902. Result:=Copy(APath,1,P-1);
  903. Delete(APath,1,P+Ord(CM));
  904. end;
  905. Var
  906. C : TComponent;
  907. S : String;
  908. begin
  909. If (APath='') then
  910. Result:=Nil
  911. else
  912. begin
  913. Result:=Root;
  914. While (APath<>'') And (Result<>Nil) do
  915. begin
  916. C:=Result;
  917. S:=Uppercase(GetNextName);
  918. Result:=C.FindComponent(S);
  919. If (Result=Nil) And (S='OWNER') then
  920. Result:=C;
  921. end;
  922. end;
  923. end;
  924. threadvar
  925. GlobalLoaded, GlobalLists: TFpList;
  926. procedure BeginGlobalLoading;
  927. begin
  928. if not Assigned(GlobalLists) then
  929. GlobalLists := TFpList.Create;
  930. GlobalLists.Add(GlobalLoaded);
  931. GlobalLoaded := TFpList.Create;
  932. end;
  933. { Notify all global components that they have been loaded completely }
  934. procedure NotifyGlobalLoading;
  935. var
  936. i: Integer;
  937. begin
  938. for i := 0 to GlobalLoaded.Count - 1 do
  939. TComponent(GlobalLoaded[i]).Loaded;
  940. end;
  941. procedure EndGlobalLoading;
  942. begin
  943. { Free the memory occupied by BeginGlobalLoading }
  944. GlobalLoaded.Free;
  945. GlobalLoaded := TFpList(GlobalLists.Last);
  946. GlobalLists.Delete(GlobalLists.Count - 1);
  947. if GlobalLists.Count = 0 then
  948. begin
  949. GlobalLists.Free;
  950. GlobalLists := nil;
  951. end;
  952. end;
  953. function CollectionsEqual(C1, C2: TCollection): Boolean;
  954. begin
  955. // !!!: Implement this
  956. CollectionsEqual:=false;
  957. end;
  958. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  959. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  960. var
  961. w : twriter;
  962. begin
  963. w:=twriter.create(s,4096);
  964. try
  965. w.root:=o;
  966. w.flookuproot:=o;
  967. w.writecollection(c);
  968. finally
  969. w.free;
  970. end;
  971. end;
  972. var
  973. s1,s2 : tmemorystream;
  974. begin
  975. result:=false;
  976. if (c1.classtype<>c2.classtype) or
  977. (c1.count<>c2.count) then
  978. exit;
  979. if c1.count = 0 then
  980. begin
  981. result:= true;
  982. exit;
  983. end;
  984. s1:=tmemorystream.create;
  985. try
  986. s2:=tmemorystream.create;
  987. try
  988. stream_collection(s1,c1,owner1);
  989. stream_collection(s2,c2,owner2);
  990. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  991. finally
  992. s2.free;
  993. end;
  994. finally
  995. s1.free;
  996. end;
  997. end;
  998. { Object conversion routines }
  999. type
  1000. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  1001. function CharToOrd(var P: Pointer): Cardinal;
  1002. begin
  1003. result:= ord(pchar(P)^);
  1004. inc(pchar(P));
  1005. end;
  1006. function WideCharToOrd(var P: Pointer): Cardinal;
  1007. begin
  1008. result:= ord(pwidechar(P)^);
  1009. inc(pwidechar(P));
  1010. end;
  1011. function Utf8ToOrd(var P:Pointer): Cardinal;
  1012. begin
  1013. // Should also check for illegal utf8 combinations
  1014. Result := Ord(PChar(P)^);
  1015. Inc(P);
  1016. if (Result and $80) <> 0 then
  1017. if (Ord(Result) and %11100000) = %11000000 then begin
  1018. Result := ((Result and %00011111) shl 6)
  1019. or (ord(PChar(P)^) and %00111111);
  1020. Inc(P);
  1021. end else if (Ord(Result) and %11110000) = %11100000 then begin
  1022. Result := ((Result and %00011111) shl 12)
  1023. or ((ord(PChar(P)^) and %00111111) shl 6)
  1024. or (ord((PChar(P)+1)^) and %00111111);
  1025. Inc(P,2);
  1026. end else begin
  1027. Result := ((ord(Result) and %00011111) shl 18)
  1028. or ((ord(PChar(P)^) and %00111111) shl 12)
  1029. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  1030. or (ord((PChar(P)+2)^) and %00111111);
  1031. Inc(P,3);
  1032. end;
  1033. end;
  1034. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  1035. procedure OutStr(s: String);
  1036. begin
  1037. if Length(s) > 0 then
  1038. Output.Write(s[1], Length(s));
  1039. end;
  1040. procedure OutLn(s: String);
  1041. begin
  1042. OutStr(s + LineEnding);
  1043. end;
  1044. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  1045. UseBytes: boolean = false);
  1046. var
  1047. res, NewStr: String;
  1048. w: Cardinal;
  1049. InString, NewInString: Boolean;
  1050. begin
  1051. if p = nil then begin
  1052. res:= '''''';
  1053. end
  1054. else
  1055. begin
  1056. res := '';
  1057. InString := False;
  1058. while P < LastP do
  1059. begin
  1060. NewInString := InString;
  1061. w := CharToOrdfunc(P);
  1062. if w = ord('''') then
  1063. begin //quote char
  1064. if not InString then
  1065. NewInString := True;
  1066. NewStr := '''''';
  1067. end
  1068. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  1069. begin //printable ascii or bytes
  1070. if not InString then
  1071. NewInString := True;
  1072. NewStr := char(w);
  1073. end
  1074. else
  1075. begin //ascii control chars, non ascii
  1076. if InString then
  1077. NewInString := False;
  1078. NewStr := '#' + IntToStr(w);
  1079. end;
  1080. if NewInString <> InString then
  1081. begin
  1082. NewStr := '''' + NewStr;
  1083. InString := NewInString;
  1084. end;
  1085. res := res + NewStr;
  1086. end;
  1087. if InString then
  1088. res := res + '''';
  1089. end;
  1090. OutStr(res);
  1091. end;
  1092. procedure OutString(s: String);
  1093. begin
  1094. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  1095. end;
  1096. procedure OutWString(W: WideString);
  1097. begin
  1098. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1099. end;
  1100. procedure OutUString(W: UnicodeString);
  1101. begin
  1102. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1103. end;
  1104. procedure OutUtf8Str(s: String);
  1105. begin
  1106. if Encoding=oteLFM then
  1107. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
  1108. else
  1109. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  1110. end;
  1111. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1112. begin
  1113. Result:=Input.ReadWord;
  1114. Result:=LEtoN(Result);
  1115. end;
  1116. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1117. begin
  1118. Result:=Input.ReadDWord;
  1119. Result:=LEtoN(Result);
  1120. end;
  1121. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1122. begin
  1123. Input.ReadBuffer(Result,sizeof(Result));
  1124. Result:=LEtoN(Result);
  1125. end;
  1126. {$ifndef FPUNONE}
  1127. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1128. function ExtendedToDouble(e : pointer) : double;
  1129. var mant : qword;
  1130. exp : smallint;
  1131. sign : boolean;
  1132. d : qword;
  1133. begin
  1134. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  1135. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  1136. mant:=LEtoN(mant);
  1137. exp:=LetoN(word(exp));
  1138. sign:=(exp and $8000)<>0;
  1139. if sign then exp:=exp and $7FFF;
  1140. case exp of
  1141. 0 : mant:=0; //if denormalized, value is too small for double,
  1142. //so it's always zero
  1143. $7FFF : exp:=2047 //either infinity or NaN
  1144. else
  1145. begin
  1146. dec(exp,16383-1023);
  1147. if (exp>=-51) and (exp<=0) then //can be denormalized
  1148. begin
  1149. mant:=mant shr (-exp);
  1150. exp:=0;
  1151. end
  1152. else
  1153. if (exp<-51) or (exp>2046) then //exponent too large.
  1154. begin
  1155. Result:=0;
  1156. exit;
  1157. end
  1158. else //normalized value
  1159. mant:=mant shl 1; //hide most significant bit
  1160. end;
  1161. end;
  1162. d:=word(exp);
  1163. d:=d shl 52;
  1164. mant:=mant shr 12;
  1165. d:=d or mant;
  1166. if sign then d:=d or $8000000000000000;
  1167. Result:=pdouble(@d)^;
  1168. end;
  1169. {$ENDIF}
  1170. {$endif}
  1171. function ReadInt(ValueType: TValueType): Int64;
  1172. begin
  1173. case ValueType of
  1174. vaInt8: Result := ShortInt(Input.ReadByte);
  1175. vaInt16: Result := SmallInt(ReadWord);
  1176. vaInt32: Result := LongInt(ReadDWord);
  1177. vaInt64: Result := Int64(ReadQWord);
  1178. end;
  1179. end;
  1180. function ReadInt: Int64;
  1181. begin
  1182. Result := ReadInt(TValueType(Input.ReadByte));
  1183. end;
  1184. {$ifndef FPUNONE}
  1185. function ReadExtended : extended;
  1186. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1187. var ext : array[0..9] of byte;
  1188. {$ENDIF}
  1189. begin
  1190. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1191. Input.ReadBuffer(ext[0],10);
  1192. Result:=ExtendedToDouble(@(ext[0]));
  1193. {$ELSE}
  1194. Input.ReadBuffer(Result,sizeof(Result));
  1195. {$ENDIF}
  1196. end;
  1197. {$endif}
  1198. function ReadSStr: String;
  1199. var
  1200. len: Byte;
  1201. begin
  1202. len := Input.ReadByte;
  1203. SetLength(Result, len);
  1204. if (len > 0) then
  1205. Input.ReadBuffer(Result[1], len);
  1206. end;
  1207. function ReadLStr: String;
  1208. var
  1209. len: DWord;
  1210. begin
  1211. len := ReadDWord;
  1212. SetLength(Result, len);
  1213. if (len > 0) then
  1214. Input.ReadBuffer(Result[1], len);
  1215. end;
  1216. function ReadWStr: WideString;
  1217. var
  1218. len: DWord;
  1219. {$IFDEF ENDIAN_BIG}
  1220. i : integer;
  1221. {$ENDIF}
  1222. begin
  1223. len := ReadDWord;
  1224. SetLength(Result, len);
  1225. if (len > 0) then
  1226. begin
  1227. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1228. {$IFDEF ENDIAN_BIG}
  1229. for i:=1 to len do
  1230. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1231. {$ENDIF}
  1232. end;
  1233. end;
  1234. function ReadUStr: UnicodeString;
  1235. var
  1236. len: DWord;
  1237. {$IFDEF ENDIAN_BIG}
  1238. i : integer;
  1239. {$ENDIF}
  1240. begin
  1241. len := ReadDWord;
  1242. SetLength(Result, len);
  1243. if (len > 0) then
  1244. begin
  1245. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1246. {$IFDEF ENDIAN_BIG}
  1247. for i:=1 to len do
  1248. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1249. {$ENDIF}
  1250. end;
  1251. end;
  1252. procedure ReadPropList(indent: String);
  1253. procedure ProcessValue(ValueType: TValueType; Indent: String);
  1254. procedure ProcessBinary;
  1255. var
  1256. ToDo, DoNow, i: LongInt;
  1257. lbuf: array[0..31] of Byte;
  1258. s: String;
  1259. begin
  1260. ToDo := ReadDWord;
  1261. OutLn('{');
  1262. while ToDo > 0 do begin
  1263. DoNow := ToDo;
  1264. if DoNow > 32 then DoNow := 32;
  1265. Dec(ToDo, DoNow);
  1266. s := Indent + ' ';
  1267. Input.ReadBuffer(lbuf, DoNow);
  1268. for i := 0 to DoNow - 1 do
  1269. s := s + IntToHex(lbuf[i], 2);
  1270. OutLn(s);
  1271. end;
  1272. OutLn(indent + '}');
  1273. end;
  1274. var
  1275. s: String;
  1276. { len: LongInt; }
  1277. IsFirst: Boolean;
  1278. {$ifndef FPUNONE}
  1279. ext: Extended;
  1280. {$endif}
  1281. begin
  1282. case ValueType of
  1283. vaList: begin
  1284. OutStr('(');
  1285. IsFirst := True;
  1286. while True do begin
  1287. ValueType := TValueType(Input.ReadByte);
  1288. if ValueType = vaNull then break;
  1289. if IsFirst then begin
  1290. OutLn('');
  1291. IsFirst := False;
  1292. end;
  1293. OutStr(Indent + ' ');
  1294. ProcessValue(ValueType, Indent + ' ');
  1295. end;
  1296. OutLn(Indent + ')');
  1297. end;
  1298. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  1299. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  1300. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  1301. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  1302. {$ifndef FPUNONE}
  1303. vaExtended: begin
  1304. ext:=ReadExtended;
  1305. Str(ext,S);// Do not use localized strings.
  1306. OutLn(S);
  1307. end;
  1308. {$endif}
  1309. vaString: begin
  1310. OutString(ReadSStr);
  1311. OutLn('');
  1312. end;
  1313. vaIdent: OutLn(ReadSStr);
  1314. vaFalse: OutLn('False');
  1315. vaTrue: OutLn('True');
  1316. vaBinary: ProcessBinary;
  1317. vaSet: begin
  1318. OutStr('[');
  1319. IsFirst := True;
  1320. while True do begin
  1321. s := ReadSStr;
  1322. if Length(s) = 0 then break;
  1323. if not IsFirst then OutStr(', ');
  1324. IsFirst := False;
  1325. OutStr(s);
  1326. end;
  1327. OutLn(']');
  1328. end;
  1329. vaLString:
  1330. begin
  1331. OutString(ReadLStr);
  1332. OutLn('');
  1333. end;
  1334. vaWString:
  1335. begin
  1336. OutWString(ReadWStr);
  1337. OutLn('');
  1338. end;
  1339. vaUString:
  1340. begin
  1341. OutWString(ReadWStr);
  1342. OutLn('');
  1343. end;
  1344. vaNil:
  1345. OutLn('nil');
  1346. vaCollection: begin
  1347. OutStr('<');
  1348. while Input.ReadByte <> 0 do begin
  1349. OutLn(Indent);
  1350. Input.Seek(-1, soFromCurrent);
  1351. OutStr(indent + ' item');
  1352. ValueType := TValueType(Input.ReadByte);
  1353. if ValueType <> vaList then
  1354. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1355. OutLn('');
  1356. ReadPropList(indent + ' ');
  1357. OutStr(indent + ' end');
  1358. end;
  1359. OutLn('>');
  1360. end;
  1361. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1362. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1363. vaDate: begin OutLn('!!Date!!'); exit end;}
  1364. vaUTF8String: begin
  1365. OutUtf8Str(ReadLStr);
  1366. OutLn('');
  1367. end;
  1368. else
  1369. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1370. end;
  1371. end;
  1372. begin
  1373. while Input.ReadByte <> 0 do begin
  1374. Input.Seek(-1, soFromCurrent);
  1375. OutStr(indent + ReadSStr + ' = ');
  1376. ProcessValue(TValueType(Input.ReadByte), Indent);
  1377. end;
  1378. end;
  1379. procedure ReadObject(indent: String);
  1380. var
  1381. b: Byte;
  1382. ObjClassName, ObjName: String;
  1383. ChildPos: LongInt;
  1384. begin
  1385. // Check for FilerFlags
  1386. b := Input.ReadByte;
  1387. if (b and $f0) = $f0 then begin
  1388. if (b and 2) <> 0 then ChildPos := ReadInt;
  1389. end else begin
  1390. b := 0;
  1391. Input.Seek(-1, soFromCurrent);
  1392. end;
  1393. ObjClassName := ReadSStr;
  1394. ObjName := ReadSStr;
  1395. OutStr(Indent);
  1396. if (b and 1) <> 0 then OutStr('inherited')
  1397. else
  1398. if (b and 4) <> 0 then OutStr('inline')
  1399. else OutStr('object');
  1400. OutStr(' ');
  1401. if ObjName <> '' then
  1402. OutStr(ObjName + ': ');
  1403. OutStr(ObjClassName);
  1404. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1405. OutLn('');
  1406. ReadPropList(indent + ' ');
  1407. while Input.ReadByte <> 0 do begin
  1408. Input.Seek(-1, soFromCurrent);
  1409. ReadObject(indent + ' ');
  1410. end;
  1411. OutLn(indent + 'end');
  1412. end;
  1413. type
  1414. PLongWord = ^LongWord;
  1415. const
  1416. signature: PChar = 'TPF0';
  1417. begin
  1418. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1419. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1420. ReadObject('');
  1421. end;
  1422. procedure ObjectBinaryToText(Input, Output: TStream);
  1423. begin
  1424. ObjectBinaryToText(Input,Output,oteDFM);
  1425. end;
  1426. procedure ObjectTextToBinary(Input, Output: TStream);
  1427. var
  1428. parser: TParser;
  1429. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1430. begin
  1431. w:=NtoLE(w);
  1432. Output.WriteWord(w);
  1433. end;
  1434. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1435. begin
  1436. lw:=NtoLE(lw);
  1437. Output.WriteDWord(lw);
  1438. end;
  1439. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1440. begin
  1441. qw:=NtoLE(qw);
  1442. Output.WriteBuffer(qw,sizeof(qword));
  1443. end;
  1444. {$ifndef FPUNONE}
  1445. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1446. procedure DoubleToExtended(d : double; e : pointer);
  1447. var mant : qword;
  1448. exp : smallint;
  1449. sign : boolean;
  1450. begin
  1451. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1452. exp :=(qword(d) shr 52) and $7FF;
  1453. sign:=(qword(d) and $8000000000000000)<>0;
  1454. case exp of
  1455. 0 : begin
  1456. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1457. begin
  1458. exp:=16383-1022;
  1459. while (mant and $8000000000000000)=0 do
  1460. begin
  1461. dec(exp);
  1462. mant:=mant shl 1;
  1463. end;
  1464. dec(exp); //don't shift, most significant bit is not hidden in extended
  1465. end;
  1466. end;
  1467. 2047 : exp:=$7FFF //either infinity or NaN
  1468. else
  1469. begin
  1470. inc(exp,16383-1023);
  1471. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1472. end;
  1473. end;
  1474. if sign then exp:=exp or $8000;
  1475. mant:=NtoLE(mant);
  1476. exp:=NtoLE(word(exp));
  1477. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1478. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1479. end;
  1480. {$ENDIF}
  1481. procedure WriteExtended(e : extended);
  1482. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1483. var ext : array[0..9] of byte;
  1484. {$ENDIF}
  1485. begin
  1486. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1487. DoubleToExtended(e,@(ext[0]));
  1488. Output.WriteBuffer(ext[0],10);
  1489. {$ELSE}
  1490. Output.WriteBuffer(e,sizeof(e));
  1491. {$ENDIF}
  1492. end;
  1493. {$endif}
  1494. procedure WriteString(s: String);
  1495. var size : byte;
  1496. begin
  1497. if length(s)>255 then size:=255
  1498. else size:=length(s);
  1499. Output.WriteByte(size);
  1500. if Length(s) > 0 then
  1501. Output.WriteBuffer(s[1], size);
  1502. end;
  1503. procedure WriteLString(Const s: String);
  1504. begin
  1505. WriteDWord(Length(s));
  1506. if Length(s) > 0 then
  1507. Output.WriteBuffer(s[1], Length(s));
  1508. end;
  1509. procedure WriteWString(Const s: WideString);
  1510. var len : longword;
  1511. {$IFDEF ENDIAN_BIG}
  1512. i : integer;
  1513. ws : widestring;
  1514. {$ENDIF}
  1515. begin
  1516. len:=Length(s);
  1517. WriteDWord(len);
  1518. if len > 0 then
  1519. begin
  1520. {$IFDEF ENDIAN_BIG}
  1521. setlength(ws,len);
  1522. for i:=1 to len do
  1523. ws[i]:=widechar(SwapEndian(word(s[i])));
  1524. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1525. {$ELSE}
  1526. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1527. {$ENDIF}
  1528. end;
  1529. end;
  1530. procedure WriteInteger(value: Int64);
  1531. begin
  1532. if (value >= -128) and (value <= 127) then begin
  1533. Output.WriteByte(Ord(vaInt8));
  1534. Output.WriteByte(byte(value));
  1535. end else if (value >= -32768) and (value <= 32767) then begin
  1536. Output.WriteByte(Ord(vaInt16));
  1537. WriteWord(word(value));
  1538. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1539. Output.WriteByte(Ord(vaInt32));
  1540. WriteDWord(longword(value));
  1541. end else begin
  1542. Output.WriteByte(ord(vaInt64));
  1543. WriteQWord(qword(value));
  1544. end;
  1545. end;
  1546. procedure ProcessWideString(const left : widestring);
  1547. var ws : widestring;
  1548. begin
  1549. ws:=left+parser.TokenWideString;
  1550. while parser.NextToken = '+' do
  1551. begin
  1552. parser.NextToken; // Get next string fragment
  1553. if not (parser.Token in [toString,toWString]) then
  1554. parser.CheckToken(toWString);
  1555. ws:=ws+parser.TokenWideString;
  1556. end;
  1557. Output.WriteByte(Ord(vaWstring));
  1558. WriteWString(ws);
  1559. end;
  1560. procedure ProcessProperty; forward;
  1561. procedure ProcessValue;
  1562. var
  1563. {$ifndef FPUNONE}
  1564. flt: Extended;
  1565. {$endif}
  1566. s: String;
  1567. stream: TMemoryStream;
  1568. begin
  1569. case parser.Token of
  1570. toInteger:
  1571. begin
  1572. WriteInteger(parser.TokenInt);
  1573. parser.NextToken;
  1574. end;
  1575. {$ifndef FPUNONE}
  1576. toFloat:
  1577. begin
  1578. Output.WriteByte(Ord(vaExtended));
  1579. flt := Parser.TokenFloat;
  1580. WriteExtended(flt);
  1581. parser.NextToken;
  1582. end;
  1583. {$endif}
  1584. toString:
  1585. begin
  1586. s := parser.TokenString;
  1587. while parser.NextToken = '+' do
  1588. begin
  1589. parser.NextToken; // Get next string fragment
  1590. case parser.Token of
  1591. toString : s:=s+parser.TokenString;
  1592. toWString : begin
  1593. ProcessWideString(s);
  1594. exit;
  1595. end
  1596. else parser.CheckToken(toString);
  1597. end;
  1598. end;
  1599. if (length(S)>255) then
  1600. begin
  1601. Output.WriteByte(Ord(vaLString));
  1602. WriteLString(S);
  1603. end
  1604. else
  1605. begin
  1606. Output.WriteByte(Ord(vaString));
  1607. WriteString(s);
  1608. end;
  1609. end;
  1610. toWString:
  1611. ProcessWideString('');
  1612. toSymbol:
  1613. begin
  1614. if CompareText(parser.TokenString, 'True') = 0 then
  1615. Output.WriteByte(Ord(vaTrue))
  1616. else if CompareText(parser.TokenString, 'False') = 0 then
  1617. Output.WriteByte(Ord(vaFalse))
  1618. else if CompareText(parser.TokenString, 'nil') = 0 then
  1619. Output.WriteByte(Ord(vaNil))
  1620. else
  1621. begin
  1622. Output.WriteByte(Ord(vaIdent));
  1623. WriteString(parser.TokenComponentIdent);
  1624. end;
  1625. Parser.NextToken;
  1626. end;
  1627. // Set
  1628. '[':
  1629. begin
  1630. parser.NextToken;
  1631. Output.WriteByte(Ord(vaSet));
  1632. if parser.Token <> ']' then
  1633. while True do
  1634. begin
  1635. parser.CheckToken(toSymbol);
  1636. WriteString(parser.TokenString);
  1637. parser.NextToken;
  1638. if parser.Token = ']' then
  1639. break;
  1640. parser.CheckToken(',');
  1641. parser.NextToken;
  1642. end;
  1643. Output.WriteByte(0);
  1644. parser.NextToken;
  1645. end;
  1646. // List
  1647. '(':
  1648. begin
  1649. parser.NextToken;
  1650. Output.WriteByte(Ord(vaList));
  1651. while parser.Token <> ')' do
  1652. ProcessValue;
  1653. Output.WriteByte(0);
  1654. parser.NextToken;
  1655. end;
  1656. // Collection
  1657. '<':
  1658. begin
  1659. parser.NextToken;
  1660. Output.WriteByte(Ord(vaCollection));
  1661. while parser.Token <> '>' do
  1662. begin
  1663. parser.CheckTokenSymbol('item');
  1664. parser.NextToken;
  1665. // ConvertOrder
  1666. Output.WriteByte(Ord(vaList));
  1667. while not parser.TokenSymbolIs('end') do
  1668. ProcessProperty;
  1669. parser.NextToken; // Skip 'end'
  1670. Output.WriteByte(0);
  1671. end;
  1672. Output.WriteByte(0);
  1673. parser.NextToken;
  1674. end;
  1675. // Binary data
  1676. '{':
  1677. begin
  1678. Output.WriteByte(Ord(vaBinary));
  1679. stream := TMemoryStream.Create;
  1680. try
  1681. parser.HexToBinary(stream);
  1682. WriteDWord(stream.Size);
  1683. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1684. finally
  1685. stream.Free;
  1686. end;
  1687. parser.NextToken;
  1688. end;
  1689. else
  1690. parser.Error(SInvalidProperty);
  1691. end;
  1692. end;
  1693. procedure ProcessProperty;
  1694. var
  1695. name: String;
  1696. begin
  1697. // Get name of property
  1698. parser.CheckToken(toSymbol);
  1699. name := parser.TokenString;
  1700. while True do begin
  1701. parser.NextToken;
  1702. if parser.Token <> '.' then break;
  1703. parser.NextToken;
  1704. parser.CheckToken(toSymbol);
  1705. name := name + '.' + parser.TokenString;
  1706. end;
  1707. WriteString(name);
  1708. parser.CheckToken('=');
  1709. parser.NextToken;
  1710. ProcessValue;
  1711. end;
  1712. procedure ProcessObject;
  1713. var
  1714. Flags: Byte;
  1715. ObjectName, ObjectType: String;
  1716. ChildPos: Integer;
  1717. begin
  1718. if parser.TokenSymbolIs('OBJECT') then
  1719. Flags :=0 { IsInherited := False }
  1720. else begin
  1721. if parser.TokenSymbolIs('INHERITED') then
  1722. Flags := 1 { IsInherited := True; }
  1723. else begin
  1724. parser.CheckTokenSymbol('INLINE');
  1725. Flags := 4;
  1726. end;
  1727. end;
  1728. parser.NextToken;
  1729. parser.CheckToken(toSymbol);
  1730. ObjectName := '';
  1731. ObjectType := parser.TokenString;
  1732. parser.NextToken;
  1733. if parser.Token = ':' then begin
  1734. parser.NextToken;
  1735. parser.CheckToken(toSymbol);
  1736. ObjectName := ObjectType;
  1737. ObjectType := parser.TokenString;
  1738. parser.NextToken;
  1739. if parser.Token = '[' then begin
  1740. parser.NextToken;
  1741. ChildPos := parser.TokenInt;
  1742. parser.NextToken;
  1743. parser.CheckToken(']');
  1744. parser.NextToken;
  1745. Flags := Flags or 2;
  1746. end;
  1747. end;
  1748. if Flags <> 0 then begin
  1749. Output.WriteByte($f0 or Flags);
  1750. if (Flags and 2) <> 0 then
  1751. WriteInteger(ChildPos);
  1752. end;
  1753. WriteString(ObjectType);
  1754. WriteString(ObjectName);
  1755. // Convert property list
  1756. while not (parser.TokenSymbolIs('END') or
  1757. parser.TokenSymbolIs('OBJECT') or
  1758. parser.TokenSymbolIs('INHERITED') or
  1759. parser.TokenSymbolIs('INLINE')) do
  1760. ProcessProperty;
  1761. Output.WriteByte(0); // Terminate property list
  1762. // Convert child objects
  1763. while not parser.TokenSymbolIs('END') do ProcessObject;
  1764. parser.NextToken; // Skip end token
  1765. Output.WriteByte(0); // Terminate property list
  1766. end;
  1767. const
  1768. signature: PChar = 'TPF0';
  1769. begin
  1770. parser := TParser.Create(Input);
  1771. try
  1772. Output.WriteBuffer(signature[0], 4);
  1773. ProcessObject;
  1774. finally
  1775. parser.Free;
  1776. end;
  1777. end;
  1778. procedure ObjectResourceToText(Input, Output: TStream);
  1779. begin
  1780. Input.ReadResHeader;
  1781. ObjectBinaryToText(Input, Output);
  1782. end;
  1783. procedure ObjectTextToResource(Input, Output: TStream);
  1784. var
  1785. StartPos, FixupInfo: LongInt;
  1786. parser: TParser;
  1787. name: String;
  1788. begin
  1789. // Get form type name
  1790. StartPos := Input.Position;
  1791. parser := TParser.Create(Input);
  1792. try
  1793. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1794. parser.NextToken;
  1795. parser.CheckToken(toSymbol);
  1796. parser.NextToken;
  1797. parser.CheckToken(':');
  1798. parser.NextToken;
  1799. parser.CheckToken(toSymbol);
  1800. name := parser.TokenString;
  1801. finally
  1802. parser.Free;
  1803. Input.Position := StartPos;
  1804. end;
  1805. name := UpperCase(name);
  1806. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1807. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1808. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1809. end;
  1810. { Utility routines }
  1811. function LineStart(Buffer, BufPos: PChar): PChar;
  1812. begin
  1813. Result := BufPos;
  1814. while Result > Buffer do begin
  1815. Dec(Result);
  1816. if Result[0] = #10 then break;
  1817. end;
  1818. end;
  1819. procedure CommonInit;
  1820. begin
  1821. SynchronizeTimeoutEvent:=RtlEventCreate;
  1822. InitCriticalSection(ThreadQueueLock);
  1823. MainThreadID:=GetCurrentThreadID;
  1824. ExternalThreads := TThreadList.Create;
  1825. TThread.FProcessorCount := CPUCount;
  1826. InitCriticalsection(ResolveSection);
  1827. InitHandlerList:=Nil;
  1828. FindGlobalComponentList:=nil;
  1829. IntConstList := TThreadList.Create;
  1830. ClassList := TThreadList.Create;
  1831. ClassAliasList := TStringList.Create;
  1832. { on unix this maps to a simple rw synchornizer }
  1833. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1834. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1835. end;
  1836. procedure CommonCleanup;
  1837. var
  1838. i: Integer;
  1839. tmpentry: TThread.PThreadQueueEntry;
  1840. begin
  1841. GlobalNameSpace.BeginWrite;
  1842. with IntConstList.LockList do
  1843. try
  1844. for i := 0 to Count - 1 do
  1845. TIntConst(Items[I]).Free;
  1846. finally
  1847. IntConstList.UnlockList;
  1848. end;
  1849. IntConstList.Free;
  1850. ClassList.Free;
  1851. ClassAliasList.Free;
  1852. RemoveFixupReferences(nil, '');
  1853. DoneCriticalsection(ResolveSection);
  1854. GlobalLists.Free;
  1855. ComponentPages.Free;
  1856. FreeAndNil(NeedResolving);
  1857. { GlobalNameSpace is an interface so this is enough }
  1858. GlobalNameSpace:=nil;
  1859. if (InitHandlerList<>Nil) then
  1860. for i := 0 to InitHandlerList.Count - 1 do
  1861. TInitHandler(InitHandlerList.Items[I]).Free;
  1862. InitHandlerList.Free;
  1863. InitHandlerList:=Nil;
  1864. FindGlobalComponentList.Free;
  1865. FindGlobalComponentList:=nil;
  1866. with ExternalThreads.LockList do
  1867. try
  1868. for i := 0 to Count - 1 do
  1869. TThread(Items[i]).Free;
  1870. finally
  1871. ExternalThreads.UnlockList;
  1872. end;
  1873. FreeAndNil(ExternalThreads);
  1874. RtlEventDestroy(SynchronizeTimeoutEvent);
  1875. { clean up the queue, but keep in mind that the entries used for Synchronize
  1876. are owned by the corresponding TThread }
  1877. while Assigned(ThreadQueueHead) do begin
  1878. tmpentry := ThreadQueueHead;
  1879. ThreadQueueHead := tmpentry^.Next;
  1880. if not Assigned(tmpentry^.SyncEvent) then
  1881. Dispose(tmpentry);
  1882. end;
  1883. DoneCriticalSection(ThreadQueueLock);
  1884. end;
  1885. { TFiler implementation }
  1886. {$i filer.inc}
  1887. { TReader implementation }
  1888. {$i reader.inc}
  1889. { TWriter implementations }
  1890. {$i writer.inc}
  1891. {$i twriter.inc}