classes.inc 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762
  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. type
  14. {$ifdef CPU16}
  15. TFilerFlagsInt = Byte;
  16. {$else CPU16}
  17. TFilerFlagsInt = LongInt;
  18. {$endif CPU16}
  19. var
  20. ClassList : TThreadlist;
  21. ClassAliasList : TStringList;
  22. {
  23. Include all message strings
  24. Add a language with IFDEF LANG_NAME
  25. just befor the final ELSE. This way English will always be the default.
  26. }
  27. {$IFDEF LANG_GERMAN}
  28. {$i constsg.inc}
  29. {$ELSE}
  30. {$IFDEF LANG_SPANISH}
  31. {$i constss.inc}
  32. {$ENDIF}
  33. {$ENDIF}
  34. { Utility routines }
  35. {$i util.inc}
  36. { TBits implementation }
  37. {$i bits.inc}
  38. { All streams implementations: }
  39. { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
  40. { TCustomMemoryStream TMemoryStream }
  41. {$i streams.inc}
  42. { TParser implementation}
  43. {$i parser.inc}
  44. { TCollection and TCollectionItem implementations }
  45. {$i collect.inc}
  46. { TList and TThreadList implementations }
  47. {$i lists.inc}
  48. { TStrings and TStringList implementations }
  49. {$i stringl.inc}
  50. { TThread implementation }
  51. { system independend threading code }
  52. var
  53. { event executed by SychronizeInternal to wake main thread if it sleeps in
  54. CheckSynchronize }
  55. SynchronizeTimeoutEvent: PRtlEvent;
  56. { the head of the queue containing the entries to be Synchronized - Nil if the
  57. queue is empty }
  58. ThreadQueueHead: TThread.PThreadQueueEntry;
  59. { the tail of the queue containing the entries to be Synchronized - Nil if the
  60. queue is empty }
  61. ThreadQueueTail: TThread.PThreadQueueEntry;
  62. { used for serialized access to the queue }
  63. ThreadQueueLock: TRtlCriticalSection;
  64. { usage counter for ThreadQueueLock }
  65. ThreadQueueLockCounter : longint;
  66. { this list holds all instances of external threads that need to be freed at
  67. the end of the program }
  68. ExternalThreads: TThreadList;
  69. { this list signals that the ExternalThreads list is cleared and thus the
  70. thread instances don't need to remove themselves }
  71. ExternalThreadsCleanup: Boolean = False;
  72. { this must be a global var, otherwise unwanted optimizations might happen in
  73. TThread.SpinWait() }
  74. SpinWaitDummy: LongWord;
  75. {$ifdef FPC_HAS_FEATURE_THREADING}
  76. threadvar
  77. {$else}
  78. var
  79. {$endif}
  80. { the instance of the current thread; in case of an external thread this is
  81. Nil until TThread.GetCurrentThread was called once (the RTLs need to ensure
  82. that threadvars are initialized with 0!) }
  83. CurrentThreadVar: TThread;
  84. type
  85. { this type is used if a thread is created using
  86. TThread.CreateAnonymousThread }
  87. TAnonymousThread = class(TThread)
  88. private
  89. fProc: TProcedure;
  90. protected
  91. procedure Execute; override;
  92. public
  93. { as in TThread aProc needs to be changed to TProc once closures are
  94. supported }
  95. constructor Create(aProc: TProcedure);
  96. end;
  97. procedure TAnonymousThread.Execute;
  98. begin
  99. fProc();
  100. end;
  101. constructor TAnonymousThread.Create(aProc: TProcedure);
  102. begin
  103. { an anonymous thread is created suspended and with FreeOnTerminate set }
  104. inherited Create(True);
  105. FreeOnTerminate := True;
  106. fProc := aProc;
  107. end;
  108. type
  109. { this type is used by TThread.GetCurrentThread if the thread does not yet
  110. have a value in CurrentThreadVar (Note: the main thread is also created as
  111. a TExternalThread) }
  112. TExternalThread = class(TThread)
  113. protected
  114. { dummy method to remove the warning }
  115. procedure Execute; override;
  116. public
  117. constructor Create;
  118. destructor Destroy; override;
  119. end;
  120. procedure TExternalThread.Execute;
  121. begin
  122. { empty }
  123. end;
  124. constructor TExternalThread.Create;
  125. begin
  126. FExternalThread := True;
  127. { the parameter is unimportant if FExternalThread is True }
  128. inherited Create(False);
  129. with ExternalThreads.LockList do
  130. try
  131. Add(Self);
  132. finally
  133. ExternalThreads.UnlockList;
  134. end;
  135. end;
  136. destructor TExternalThread.Destroy;
  137. begin
  138. inherited;
  139. if not ExternalThreadsCleanup then
  140. with ExternalThreads.LockList do
  141. try
  142. Extract(Self);
  143. finally
  144. ExternalThreads.UnlockList;
  145. end;
  146. end;
  147. function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
  148. var
  149. FreeThread: Boolean;
  150. Thread: TThread absolute ThreadObjPtr;
  151. begin
  152. { if Suspend checks FSuspended before doing anything, make sure it }
  153. { knows we're currently not suspended (this flag may have been set }
  154. { to true if CreateSuspended was true) }
  155. // Thread.FSuspended:=false;
  156. // wait until AfterConstruction has been called, so we cannot
  157. // free ourselves before TThread.Create has finished
  158. // (since that one may check our VTM in case of $R+, and
  159. // will call the AfterConstruction method in all cases)
  160. // Thread.Suspend;
  161. try
  162. { The thread may be already terminated at this point, e.g. if it was intially
  163. suspended, or if it wasn't ever scheduled for execution for whatever reason.
  164. So bypass user code if terminated. }
  165. if not Thread.Terminated then begin
  166. CurrentThreadVar := Thread;
  167. Thread.Execute;
  168. end;
  169. except
  170. Thread.FFatalException := TObject(AcquireExceptionObject);
  171. end;
  172. FreeThread := Thread.FFreeOnTerminate;
  173. Result := Thread.FReturnValue;
  174. Thread.FFinished := True;
  175. Thread.DoTerminate;
  176. if FreeThread then
  177. Thread.Free;
  178. {$ifdef FPC_HAS_FEATURE_THREADING}
  179. EndThread(Result);
  180. {$endif}
  181. end;
  182. { system-dependent code }
  183. {$i tthread.inc}
  184. constructor TThread.Create(CreateSuspended: Boolean;
  185. const StackSize: SizeUInt);
  186. begin
  187. inherited Create;
  188. {$ifdef FPC_HAS_FEATURE_THREADING}
  189. InterlockedIncrement(ThreadQueueLockCounter);
  190. {$endif}
  191. if FExternalThread then
  192. {$ifdef FPC_HAS_FEATURE_THREADING}
  193. FThreadID := GetCurrentThreadID
  194. {$else}
  195. FThreadID := 0{GetCurrentThreadID}
  196. {$endif}
  197. else
  198. SysCreate(CreateSuspended, StackSize);
  199. end;
  200. destructor TThread.Destroy;
  201. begin
  202. if not FExternalThread then begin
  203. SysDestroy;
  204. {$ifdef FPC_HAS_FEATURE_THREADING}
  205. if FHandle <> TThreadID(0) then
  206. CloseThread(FHandle);
  207. {$endif}
  208. end;
  209. RemoveQueuedEvents(Self);
  210. DoneSynchronizeEvent;
  211. {$ifdef FPC_HAS_FEATURE_THREADING}
  212. if InterlockedDecrement(ThreadQueueLockCounter)=0 then
  213. DoneCriticalSection(ThreadQueueLock);
  214. {$endif}
  215. { set CurrentThreadVar to Nil? }
  216. inherited Destroy;
  217. end;
  218. procedure TThread.Start;
  219. begin
  220. { suspend/resume are now deprecated in Delphi (they also don't work
  221. on most platforms in FPC), so a different method was required
  222. to start a thread if it's create with fSuspended=true -> that's
  223. what this method is for. }
  224. Resume;
  225. end;
  226. function TThread.GetSuspended: Boolean;
  227. begin
  228. GetSuspended:=FSuspended;
  229. end;
  230. procedure TThread.Terminate;
  231. begin
  232. FTerminated := True;
  233. TerminatedSet;
  234. end;
  235. Procedure TThread.TerminatedSet;
  236. begin
  237. // Empty, must be overridden.
  238. end;
  239. procedure TThread.AfterConstruction;
  240. begin
  241. inherited AfterConstruction;
  242. // enable for all platforms once http://bugs.freepascal.org/view.php?id=16884
  243. // is fixed for all platforms (in case the fix for non-unix platforms also
  244. // requires this field at least)
  245. {$if defined(unix) or defined(windows) or defined(os2) or defined(hasamiga)}
  246. if not FExternalThread and not FInitialSuspended then
  247. Resume;
  248. {$endif}
  249. end;
  250. procedure ExecuteThreadQueueEntry(aEntry: TThread.PThreadQueueEntry);
  251. begin
  252. if Assigned(aEntry^.Method) then
  253. aEntry^.Method()
  254. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  255. else
  256. if Assigned(aEntry^.ThreadProc) then
  257. aEntry^.ThreadProc
  258. {$endif}
  259. end;
  260. procedure ThreadQueueAppend(aEntry: TThread.PThreadQueueEntry; aQueueIfMain: Boolean);
  261. var
  262. thd: TThread;
  263. issync: Boolean;
  264. begin
  265. { do we really need a synchronized call? }
  266. {$ifdef FPC_HAS_FEATURE_THREADING}
  267. if (GetCurrentThreadID = MainThreadID) and (not aQueueIfMain or not IsMultiThread) then
  268. {$endif}
  269. begin
  270. try
  271. ExecuteThreadQueueEntry(aEntry);
  272. finally
  273. if not Assigned(aEntry^.SyncEvent) then
  274. Dispose(aEntry);
  275. end;
  276. {$ifdef FPC_HAS_FEATURE_THREADING}
  277. end else begin
  278. { store thread and whether we're dealing with a synchronized event; the
  279. event record itself might already be freed after the ThreadQueueLock is
  280. released (in case of a Queue() call; for a Synchronize() call the record
  281. will stay valid, thus accessing SyncEvent later on (if issync is true) is
  282. okay) }
  283. thd := aEntry^.Thread;
  284. issync := Assigned(aEntry^.SyncEvent);
  285. System.EnterCriticalSection(ThreadQueueLock);
  286. try
  287. { add the entry to the thread queue }
  288. if Assigned(ThreadQueueTail) then begin
  289. ThreadQueueTail^.Next := aEntry;
  290. end else
  291. ThreadQueueHead := aEntry;
  292. ThreadQueueTail := aEntry;
  293. finally
  294. System.LeaveCriticalSection(ThreadQueueLock);
  295. end;
  296. { ensure that the main thread knows that something awaits }
  297. RtlEventSetEvent(SynchronizeTimeoutEvent);
  298. if assigned(WakeMainThread) then
  299. WakeMainThread(thd);
  300. { is this a Synchronize or Queue entry? }
  301. if issync then begin
  302. RtlEventWaitFor(aEntry^.SyncEvent);
  303. if Assigned(aEntry^.Exception) then
  304. raise aEntry^.Exception;
  305. end;
  306. {$endif def FPC_HAS_FEATURE_THREADING}
  307. end;
  308. end;
  309. procedure TThread.InitSynchronizeEvent;
  310. begin
  311. if Assigned(FSynchronizeEntry) then
  312. Exit;
  313. New(FSynchronizeEntry);
  314. FillChar(FSynchronizeEntry^, SizeOf(TThreadQueueEntry), 0);
  315. FSynchronizeEntry^.Thread := Self;
  316. FSynchronizeEntry^.ThreadID := ThreadID;
  317. {$ifdef FPC_HAS_FEATURE_THREADING}
  318. FSynchronizeEntry^.SyncEvent := RtlEventCreate;
  319. {$else}
  320. FSynchronizeEntry^.SyncEvent := nil{RtlEventCreate};
  321. {$endif}
  322. end;
  323. procedure TThread.DoneSynchronizeEvent;
  324. begin
  325. if not Assigned(FSynchronizeEntry) then
  326. Exit;
  327. {$ifdef FPC_HAS_FEATURE_THREADING}
  328. RtlEventDestroy(FSynchronizeEntry^.SyncEvent);
  329. {$endif}
  330. Dispose(FSynchronizeEntry);
  331. FSynchronizeEntry := Nil;
  332. end;
  333. class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
  334. var
  335. syncentry: PThreadQueueEntry;
  336. thread: TThread;
  337. begin
  338. {$ifdef FPC_HAS_FEATURE_THREADING}
  339. if Assigned(AThread) and (AThread.ThreadID = GetCurrentThreadID) then
  340. {$else}
  341. if Assigned(AThread) then
  342. {$endif}
  343. thread := AThread
  344. else if Assigned(CurrentThreadVar) then
  345. thread := CurrentThreadVar
  346. else begin
  347. thread := Nil;
  348. { use a local synchronize event }
  349. New(syncentry);
  350. FillChar(syncentry^, SizeOf(TThreadQueueEntry), 0);
  351. {$ifdef FPC_HAS_FEATURE_THREADING}
  352. syncentry^.ThreadID := GetCurrentThreadID;
  353. syncentry^.SyncEvent := RtlEventCreate;
  354. {$else}
  355. syncentry^.ThreadID := 0{GetCurrentThreadID};
  356. syncentry^.SyncEvent := nil{RtlEventCreate};
  357. {$endif}
  358. end;
  359. if Assigned(thread) then begin
  360. { the Synchronize event is instantiated on demand }
  361. thread.InitSynchronizeEvent;
  362. syncentry := thread.FSynchronizeEntry;
  363. end;
  364. syncentry^.Exception := Nil;
  365. syncentry^.Method := AMethod;
  366. try
  367. ThreadQueueAppend(syncentry, False);
  368. finally
  369. syncentry^.Method := Nil;
  370. syncentry^.Next := Nil;
  371. if not Assigned(thread) then begin
  372. { clean up again }
  373. {$ifdef FPC_HAS_FEATURE_THREADING}
  374. RtlEventDestroy(syncentry^.SyncEvent);
  375. {$endif}
  376. Dispose(syncentry);
  377. end;
  378. end;
  379. end;
  380. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  381. class procedure TThread.Synchronize(AThread: TThread; AProcedure: TThreadProcedure);
  382. var
  383. syncentry: PThreadQueueEntry;
  384. thread: TThread;
  385. begin
  386. {$ifdef FPC_HAS_FEATURE_THREADING}
  387. if Assigned(AThread) and (AThread.ThreadID = GetCurrentThreadID) then
  388. {$else}
  389. if Assigned(AThread) then
  390. {$endif}
  391. thread := AThread
  392. else if Assigned(CurrentThreadVar) then
  393. thread := CurrentThreadVar
  394. else begin
  395. thread := Nil;
  396. { use a local synchronize event }
  397. New(syncentry);
  398. FillChar(syncentry^, SizeOf(TThreadQueueEntry), 0);
  399. {$ifdef FPC_HAS_FEATURE_THREADING}
  400. syncentry^.ThreadID := GetCurrentThreadID;
  401. syncentry^.SyncEvent := RtlEventCreate;
  402. {$else}
  403. syncentry^.ThreadID := 0{GetCurrentThreadID};
  404. syncentry^.SyncEvent := nil{RtlEventCreate};
  405. {$endif}
  406. end;
  407. if Assigned(thread) then begin
  408. { the Synchronize event is instantiated on demand }
  409. thread.InitSynchronizeEvent;
  410. syncentry := thread.FSynchronizeEntry;
  411. end;
  412. syncentry^.Exception := Nil;
  413. syncentry^.ThreadProc := AProcedure;
  414. try
  415. ThreadQueueAppend(syncentry, False);
  416. finally
  417. syncentry^.ThreadProc := Nil;
  418. syncentry^.Next := Nil;
  419. if not Assigned(thread) then begin
  420. { clean up again }
  421. {$ifdef FPC_HAS_FEATURE_THREADING}
  422. RtlEventDestroy(syncentry^.SyncEvent);
  423. {$endif}
  424. Dispose(syncentry);
  425. end;
  426. end;
  427. end;
  428. {$endif}
  429. procedure TThread.Synchronize(AMethod: TThreadMethod);
  430. begin
  431. TThread.Synchronize(self,AMethod);
  432. end;
  433. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  434. procedure TThread.Synchronize(AProcedure: TThreadProcedure);
  435. begin
  436. TThread.Synchronize(self,AProcedure);
  437. end;
  438. {$endif}
  439. Function PopThreadQueueHead : TThread.PThreadQueueEntry;
  440. begin
  441. Result:=ThreadQueueHead;
  442. if (Result<>Nil) then
  443. begin
  444. {$ifdef FPC_HAS_FEATURE_THREADING}
  445. System.EnterCriticalSection(ThreadQueueLock);
  446. try
  447. {$endif}
  448. Result:=ThreadQueueHead;
  449. if Result<>Nil then
  450. ThreadQueueHead:=ThreadQueueHead^.Next;
  451. if Not Assigned(ThreadQueueHead) then
  452. ThreadQueueTail := Nil;
  453. {$ifdef FPC_HAS_FEATURE_THREADING}
  454. finally
  455. System.LeaveCriticalSection(ThreadQueueLock);
  456. end;
  457. {$endif}
  458. end;
  459. end;
  460. function CheckSynchronize(timeout : longint=0) : boolean;
  461. { assumes being called from GUI thread }
  462. var
  463. ExceptObj: TObject;
  464. tmpentry: TThread.PThreadQueueEntry;
  465. begin
  466. result:=false;
  467. { first sanity check }
  468. if Not IsMultiThread then
  469. Exit
  470. {$ifdef FPC_HAS_FEATURE_THREADING}
  471. { second sanity check }
  472. else if GetCurrentThreadID<>MainThreadID then
  473. raise EThread.CreateFmt(SCheckSynchronizeError,[GetCurrentThreadID]);
  474. if timeout>0 then
  475. RtlEventWaitFor(SynchronizeTimeoutEvent,timeout)
  476. else
  477. RtlEventResetEvent(SynchronizeTimeoutEvent);
  478. tmpentry := PopThreadQueueHead;
  479. while Assigned(tmpentry) do
  480. begin
  481. { step 2: execute the method }
  482. exceptobj := Nil;
  483. try
  484. ExecuteThreadQueueEntry(tmpentry);
  485. except
  486. exceptobj := TObject(AcquireExceptionObject);
  487. end;
  488. { step 3: error handling and cleanup }
  489. if Assigned(tmpentry^.SyncEvent) then
  490. begin
  491. { for Synchronize entries we pass back the Exception and trigger
  492. the event that Synchronize waits in }
  493. tmpentry^.Exception := exceptobj;
  494. RtlEventSetEvent(tmpentry^.SyncEvent)
  495. end
  496. else
  497. begin
  498. { for Queue entries we dispose the entry and raise the exception }
  499. Dispose(tmpentry);
  500. if Assigned(exceptobj) then
  501. raise exceptobj;
  502. end;
  503. tmpentry := PopThreadQueueHead;
  504. end
  505. {$endif};
  506. end;
  507. class function TThread.GetCurrentThread: TThread;
  508. begin
  509. { if this is the first time GetCurrentThread is called for an external thread
  510. we need to create a corresponding TExternalThread instance }
  511. Result := CurrentThreadVar;
  512. if not Assigned(Result) then begin
  513. Result := TExternalThread.Create;
  514. CurrentThreadVar := Result;
  515. end;
  516. end;
  517. class function TThread.GetIsSingleProcessor: Boolean;
  518. begin
  519. Result := FProcessorCount <= 1;
  520. end;
  521. procedure TThread.Queue(aMethod: TThreadMethod);
  522. begin
  523. Queue(Self, aMethod);
  524. end;
  525. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  526. procedure TThread.Queue(aProcedure: TThreadProcedure);
  527. begin
  528. Queue(Self, aProcedure);
  529. end;
  530. {$endif}
  531. class procedure TThread.Queue(aThread: TThread; aMethod: TThreadMethod); static;
  532. begin
  533. InternalQueue(aThread, aMethod, False);
  534. end;
  535. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  536. class procedure TThread.Queue(aThread: TThread; aProcedure: TThreadProcedure); static;
  537. begin
  538. InternalQueue(aThread, aProcedure, False);
  539. end;
  540. {$endif}
  541. class procedure TThread.InternalQueue(aThread: TThread; aMethod: TThreadMethod; aQueueIfMain: Boolean); static;
  542. var
  543. queueentry: PThreadQueueEntry;
  544. begin
  545. New(queueentry);
  546. FillChar(queueentry^, SizeOf(TThreadQueueEntry), 0);
  547. queueentry^.Thread := aThread;
  548. {$ifdef FPC_HAS_FEATURE_THREADING}
  549. queueentry^.ThreadID := GetCurrentThreadID;
  550. {$else}
  551. queueentry^.ThreadID := 0{GetCurrentThreadID};
  552. {$endif}
  553. queueentry^.Method := aMethod;
  554. { the queueentry is freed by CheckSynchronize (or by RemoveQueuedEvents) }
  555. ThreadQueueAppend(queueentry, aQueueIfMain);
  556. end;
  557. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  558. class procedure TThread.InternalQueue(aThread: TThread; aProcedure: TThreadProcedure; aQueueIfMain: Boolean); static;
  559. var
  560. queueentry: PThreadQueueEntry;
  561. begin
  562. New(queueentry);
  563. FillChar(queueentry^, SizeOf(TThreadQueueEntry), 0);
  564. queueentry^.Thread := aThread;
  565. {$ifdef FPC_HAS_FEATURE_THREADING}
  566. queueentry^.ThreadID := GetCurrentThreadID;
  567. {$else}
  568. queueentry^.ThreadID := 0{GetCurrentThreadID};
  569. {$endif}
  570. queueentry^.ThreadProc := aProcedure;
  571. { the queueentry is freed by CheckSynchronize (or by RemoveQueuedEvents) }
  572. ThreadQueueAppend(queueentry, aQueueIfMain);
  573. end;
  574. {$endif}
  575. procedure TThread.ForceQueue(aMethod: TThreadMethod);
  576. begin
  577. ForceQueue(Self, aMethod);
  578. end;
  579. class procedure TThread.ForceQueue(aThread: TThread; aMethod: TThreadMethod); static;
  580. begin
  581. InternalQueue(aThread, aMethod, True);
  582. end;
  583. class procedure TThread.RemoveQueuedEvents(aThread: TThread; aMethod: TThreadMethod);
  584. var
  585. entry, tmpentry, lastentry: PThreadQueueEntry;
  586. begin
  587. { anything to do at all? }
  588. if not Assigned(aThread) and not Assigned(aMethod) then
  589. Exit;
  590. {$ifdef FPC_HAS_FEATURE_THREADING}
  591. System.EnterCriticalSection(ThreadQueueLock);
  592. try
  593. {$endif}
  594. lastentry := Nil;
  595. entry := ThreadQueueHead;
  596. while Assigned(entry) do begin
  597. if
  598. { only entries not added by Synchronize }
  599. not Assigned(entry^.SyncEvent)
  600. { check for the thread }
  601. and (not Assigned(aThread) or (entry^.Thread = aThread) or (entry^.ThreadID = aThread.ThreadID))
  602. { check for the method }
  603. and (not Assigned(aMethod) or
  604. (
  605. (TMethod(entry^.Method).Code = TMethod(aMethod).Code) and
  606. (TMethod(entry^.Method).Data = TMethod(aMethod).Data)
  607. ))
  608. then begin
  609. { ok, we need to remove this entry }
  610. tmpentry := entry;
  611. if Assigned(lastentry) then
  612. lastentry^.Next := entry^.Next;
  613. entry := entry^.Next;
  614. if ThreadQueueHead = tmpentry then
  615. ThreadQueueHead := entry;
  616. if ThreadQueueTail = tmpentry then
  617. ThreadQueueTail := lastentry;
  618. { only dispose events added by Queue }
  619. if not Assigned(tmpentry^.SyncEvent) then
  620. Dispose(tmpentry);
  621. end else begin
  622. { leave this entry }
  623. lastentry := entry;
  624. entry := entry^.Next;
  625. end;
  626. end;
  627. {$ifdef FPC_HAS_FEATURE_THREADING}
  628. finally
  629. System.LeaveCriticalSection(ThreadQueueLock);
  630. end;
  631. {$endif}
  632. end;
  633. class procedure TThread.RemoveQueuedEvents(aMethod: TThreadMethod);
  634. begin
  635. RemoveQueuedEvents(Nil, aMethod);
  636. end;
  637. class procedure TThread.RemoveQueuedEvents(aThread: TThread);
  638. begin
  639. RemoveQueuedEvents(aThread, Nil);
  640. end;
  641. class function TThread.CheckTerminated: Boolean;
  642. begin
  643. { this method only works with threads created by TThread, so we can make a
  644. shortcut here }
  645. if not Assigned(CurrentThreadVar) then
  646. raise EThreadExternalException.Create(SThreadExternal);
  647. Result := CurrentThreadVar.FTerminated;
  648. end;
  649. class procedure TThread.SetReturnValue(aValue: Integer);
  650. begin
  651. { this method only works with threads created by TThread, so we can make a
  652. shortcut here }
  653. if not Assigned(CurrentThreadVar) then
  654. raise EThreadExternalException.Create(SThreadExternal);
  655. CurrentThreadVar.FReturnValue := aValue;
  656. end;
  657. class function TThread.CreateAnonymousThread(aProc: TProcedure): TThread;
  658. begin
  659. if not Assigned(aProc) then
  660. raise Exception.Create(SNoProcGiven);
  661. Result := TAnonymousThread.Create(aProc);
  662. end;
  663. class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
  664. begin
  665. {$ifdef FPC_HAS_FEATURE_THREADING}
  666. SetThreadDebugName(aThreadID, aThreadName);
  667. {$endif}
  668. end;
  669. class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
  670. begin
  671. {$ifdef FPC_HAS_FEATURE_THREADING}
  672. SetThreadDebugName(aThreadID, aThreadName);
  673. {$endif}
  674. end;
  675. class procedure TThread.Yield;
  676. begin
  677. {$ifdef FPC_HAS_FEATURE_THREADING}
  678. ThreadSwitch;
  679. {$endif}
  680. end;
  681. class procedure TThread.Sleep(aMilliseconds: Cardinal);
  682. begin
  683. SysUtils.Sleep(aMilliseconds);
  684. end;
  685. class procedure TThread.SpinWait(aIterations: LongWord);
  686. var
  687. i: LongWord;
  688. begin
  689. { yes, it's just a simple busy wait to burn some cpu cycles... and as the job
  690. of this loop is to burn CPU cycles we switch off any optimizations that
  691. could interfere with this (e.g. loop unrolling) }
  692. { Do *NOT* do $PUSH, $OPTIMIZATIONS OFF, <code>, $POP because optimization is
  693. not a local switch, which means $PUSH/POP doesn't affect it, so that turns
  694. off *ALL* optimizations for code below this point. Thanks to this we shipped
  695. large parts of the classes unit with optimizations off between 2012-12-27
  696. and 2014-06-06.
  697. Instead, use a global var for the spinlock, because that is always handled
  698. as volatile, so the access won't be optimized away by the compiler. (KB) }
  699. for i:=1 to aIterations do
  700. begin
  701. Inc(SpinWaitDummy); // SpinWaitDummy *MUST* be global
  702. end;
  703. end;
  704. {$ifndef HAS_TTHREAD_GETSYSTEMTIMES}
  705. class procedure TThread.GetSystemTimes(out aSystemTimes: TSystemTimes);
  706. begin
  707. { by default we just return a zeroed out record }
  708. FillChar(aSystemTimes, SizeOf(aSystemTimes), 0);
  709. end;
  710. {$endif}
  711. class function TThread.GetTickCount: LongWord;
  712. begin
  713. Result := SysUtils.GetTickCount;
  714. end;
  715. class function TThread.GetTickCount64: QWord;
  716. begin
  717. Result := SysUtils.GetTickCount64;
  718. end;
  719. { TSimpleThread allows objects to create a threading method without defining
  720. a new thread class }
  721. Type
  722. TSimpleThread = class(TThread)
  723. private
  724. FExecuteMethod: TThreadExecuteHandler;
  725. protected
  726. procedure Execute; override;
  727. public
  728. constructor Create(ExecuteMethod: TThreadExecuteHandler; AOnterminate : TNotifyEvent);
  729. end;
  730. TSimpleStatusThread = class(TThread)
  731. private
  732. FExecuteMethod: TThreadExecuteStatusHandler;
  733. FStatus : String;
  734. FOnStatus : TThreadStatusNotifyEvent;
  735. protected
  736. procedure Execute; override;
  737. Procedure DoStatus;
  738. Procedure SetStatus(Const AStatus : String);
  739. public
  740. constructor Create(ExecuteMethod: TThreadExecuteStatusHandler; AOnStatus : TThreadStatusNotifyEvent; AOnterminate : TNotifyEvent);
  741. end;
  742. TSimpleProcThread = class(TThread)
  743. private
  744. FExecuteMethod: TThreadExecuteCallBack;
  745. FCallOnTerminate : TNotifyCallBack;
  746. FData : Pointer;
  747. protected
  748. Procedure TerminateCallBack(Sender : TObject);
  749. procedure Execute; override;
  750. public
  751. constructor Create(ExecuteMethod: TThreadExecuteCallBack; AData : Pointer; AOnterminate : TNotifyCallBack);
  752. end;
  753. TSimpleStatusProcThread = class(TThread)
  754. private
  755. FExecuteMethod: TThreadExecuteStatusCallBack;
  756. FCallOnTerminate : TNotifyCallBack;
  757. FStatus : String;
  758. FOnStatus : TThreadStatusNotifyCallBack;
  759. FData : Pointer;
  760. protected
  761. procedure Execute; override;
  762. Procedure DoStatus;
  763. Procedure SetStatus(Const AStatus : String);
  764. Procedure TerminateCallBack(Sender : TObject);
  765. public
  766. constructor Create(ExecuteMethod: TThreadExecuteStatusCallBack; AData : Pointer; AOnStatus : TThreadStatusNotifyCallBack; AOnterminate : TNotifyCallBack);
  767. end;
  768. { TSimpleThread }
  769. constructor TSimpleThread.Create(ExecuteMethod: TThreadExecuteHandler; AOnTerminate: TNotifyEvent);
  770. begin
  771. FExecuteMethod := ExecuteMethod;
  772. OnTerminate := AOnTerminate;
  773. inherited Create(False);
  774. end;
  775. procedure TSimpleThread.Execute;
  776. begin
  777. FreeOnTerminate := True;
  778. FExecuteMethod;
  779. end;
  780. { TSimpleStatusThread }
  781. constructor TSimpleStatusThread.Create(ExecuteMethod: TThreadExecuteStatusHandler;AOnStatus : TThreadStatusNotifyEvent; AOnTerminate: TNotifyEvent);
  782. begin
  783. FExecuteMethod := ExecuteMethod;
  784. OnTerminate := AOnTerminate;
  785. FOnStatus:=AOnStatus;
  786. FStatus:='';
  787. inherited Create(False);
  788. end;
  789. procedure TSimpleStatusThread.Execute;
  790. begin
  791. FreeOnTerminate := True;
  792. FExecuteMethod(@SetStatus);
  793. end;
  794. procedure TSimpleStatusThread.SetStatus(Const AStatus : String);
  795. begin
  796. If (AStatus=FStatus) then
  797. exit;
  798. FStatus:=AStatus;
  799. If Assigned(FOnStatus) then
  800. Synchronize(@DoStatus);
  801. end;
  802. procedure TSimpleStatusThread.DoStatus;
  803. begin
  804. FOnStatus(Self,FStatus);
  805. end;
  806. { TSimpleProcThread }
  807. constructor TSimpleProcThread.Create(ExecuteMethod: TThreadExecuteCallBack; AData : Pointer; AOnTerminate: TNotifyCallBack);
  808. begin
  809. FExecuteMethod := ExecuteMethod;
  810. FCallOnTerminate := AOnTerminate;
  811. FData:=AData;
  812. If Assigned(FCallOnTerminate) then
  813. OnTerminate:=@TerminateCallBack;
  814. inherited Create(False);
  815. end;
  816. procedure TSimpleProcThread.Execute;
  817. begin
  818. FreeOnTerminate := True;
  819. FExecuteMethod(FData);
  820. end;
  821. procedure TSimpleProcThread.TerminateCallBack(Sender : TObject);
  822. begin
  823. if Assigned(FCallOnTerminate) then
  824. FCallOnTerminate(Sender,FData);
  825. end;
  826. { TSimpleStatusProcThread }
  827. constructor TSimpleStatusProcThread.Create(ExecuteMethod: TThreadExecuteStatusCallback; AData : Pointer; AOnStatus : TThreadStatusNotifyCallBack; AOnTerminate: TNotifyCallBack);
  828. begin
  829. FExecuteMethod := ExecuteMethod;
  830. FCallOnTerminate := AOnTerminate;
  831. FData:=AData;
  832. If Assigned(FCallOnTerminate) then
  833. OnTerminate:=@TerminateCallBack;
  834. FOnStatus:=AOnStatus;
  835. FStatus:='';
  836. inherited Create(False);
  837. end;
  838. procedure TSimpleStatusProcThread.Execute;
  839. begin
  840. FreeOnTerminate := True;
  841. FExecuteMethod(FData,@SetStatus);
  842. end;
  843. procedure TSimpleStatusProcThread.SetStatus(Const AStatus : String);
  844. begin
  845. If (AStatus=FStatus) then
  846. exit;
  847. FStatus:=AStatus;
  848. If Assigned(FOnStatus) then
  849. Synchronize(@DoStatus);
  850. end;
  851. procedure TSimpleStatusProcThread.DoStatus;
  852. begin
  853. FOnStatus(Self,FData,FStatus);
  854. end;
  855. procedure TSimpleStatusProcThread.TerminateCallBack(Sender : TObject);
  856. begin
  857. if Assigned(FCallOnTerminate) then
  858. FCallOnTerminate(Sender,FData);
  859. end;
  860. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteHandler; AOnTerminate : TNotifyEvent = Nil) : TThread;
  861. begin
  862. Result:=TSimpleThread.Create(AMethod,AOnTerminate);
  863. end;
  864. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteCallback; AData : Pointer; AOnTerminate : TNotifyCallback = Nil) : TThread;
  865. begin
  866. Result:=TSimpleProcThread.Create(AMethod,AData,AOnTerminate);
  867. end;
  868. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteStatusHandler; AOnStatus : TThreadStatusNotifyEvent; AOnTerminate : TNotifyEvent = Nil) : TThread;
  869. begin
  870. If Not Assigned(AOnStatus) then
  871. Raise EThread.Create(SErrStatusCallBackRequired);
  872. Result:=TSimpleStatusThread.Create(AMethod,AOnStatus,AOnTerminate);
  873. end;
  874. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteStatusCallback; AOnStatus : TThreadStatusNotifyCallback;AData : Pointer = Nil; AOnTerminate : TNotifyCallBack = Nil) : TThread;
  875. begin
  876. If Not Assigned(AOnStatus) then
  877. Raise EThread.Create(SErrStatusCallBackRequired);
  878. Result:=TSimpleStatusProcThread.Create(AMethod,AData,AOnStatus,AOnTerminate);
  879. end;
  880. { TPersistent implementation }
  881. {$i persist.inc }
  882. {$i sllist.inc}
  883. {$i resref.inc}
  884. { TComponent implementation }
  885. {$i compon.inc}
  886. { TBasicAction implementation }
  887. {$i action.inc}
  888. { TDataModule implementation }
  889. {$i dm.inc}
  890. { Class and component registration routines }
  891. {$I cregist.inc}
  892. { Interface related stuff }
  893. {$I intf.inc}
  894. {**********************************************************************
  895. * Miscellaneous procedures and functions *
  896. **********************************************************************}
  897. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings; AddEmptyStrings : Boolean = False): Integer;
  898. var
  899. b, c : pchar;
  900. procedure SkipWhitespace;
  901. begin
  902. while (c^ in Whitespace) do
  903. inc (c);
  904. end;
  905. procedure AddString;
  906. var
  907. l : integer;
  908. s : string;
  909. begin
  910. l := c-b;
  911. if (l > 0) or AddEmptyStrings then
  912. begin
  913. if assigned(Strings) then
  914. begin
  915. setlength(s, l);
  916. if l>0 then
  917. move (b^, s[1],l*SizeOf(char));
  918. Strings.Add (s);
  919. end;
  920. inc (result);
  921. end;
  922. end;
  923. var
  924. quoted : char;
  925. begin
  926. result := 0;
  927. c := Content;
  928. Quoted := #0;
  929. Separators := Separators + [#13, #10] - ['''','"'];
  930. SkipWhitespace;
  931. b := c;
  932. while (c^ <> #0) do
  933. begin
  934. if (c^ = Quoted) then
  935. begin
  936. if ((c+1)^ = Quoted) then
  937. inc (c)
  938. else
  939. Quoted := #0
  940. end
  941. else if (Quoted = #0) and (c^ in ['''','"']) then
  942. Quoted := c^;
  943. if (Quoted = #0) and (c^ in Separators) then
  944. begin
  945. AddString;
  946. inc (c);
  947. SkipWhitespace;
  948. b := c;
  949. end
  950. else
  951. inc (c);
  952. end;
  953. if (c <> b) then
  954. AddString;
  955. end;
  956. { Point and rectangle constructors }
  957. function Point(AX, AY: Integer): TPoint;
  958. begin
  959. with Result do
  960. begin
  961. X := AX;
  962. Y := AY;
  963. end;
  964. end;
  965. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  966. begin
  967. with Result do
  968. begin
  969. X := AX;
  970. Y := AY;
  971. end;
  972. end;
  973. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  974. begin
  975. with Result do
  976. begin
  977. Left := ALeft;
  978. Top := ATop;
  979. Right := ARight;
  980. Bottom := ABottom;
  981. end;
  982. end;
  983. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  984. begin
  985. with Result do
  986. begin
  987. Left := ALeft;
  988. Top := ATop;
  989. Right := ALeft + AWidth;
  990. Bottom := ATop + AHeight;
  991. end;
  992. end;
  993. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  994. begin
  995. { lazy, but should work }
  996. result:=QWord(P1)=QWord(P2);
  997. end;
  998. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  999. begin
  1000. { lazy, but should work }
  1001. result:=DWord(P1)=DWord(P2);
  1002. end;
  1003. function InvalidPoint(X, Y: Integer): Boolean;
  1004. begin
  1005. result:=(X=-1) and (Y=-1);
  1006. end;
  1007. function InvalidPoint(const At: TPoint): Boolean;
  1008. begin
  1009. result:=(At.x=-1) and (At.y=-1);
  1010. end;
  1011. function InvalidPoint(const At: TSmallPoint): Boolean;
  1012. begin
  1013. result:=(At.x=-1) and (At.y=-1);
  1014. end;
  1015. { Object filing routines }
  1016. var
  1017. IntConstList: TThreadList;
  1018. type
  1019. TIntConst = class
  1020. IntegerType: PTypeInfo; // The integer type RTTI pointer
  1021. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  1022. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  1023. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  1024. AIntToIdent: TIntToIdent);
  1025. end;
  1026. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  1027. AIntToIdent: TIntToIdent);
  1028. begin
  1029. IntegerType := AIntegerType;
  1030. IdentToIntFn := AIdentToInt;
  1031. IntToIdentFn := AIntToIdent;
  1032. end;
  1033. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  1034. IntToIdentFn: TIntToIdent);
  1035. begin
  1036. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  1037. end;
  1038. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  1039. var
  1040. i: Integer;
  1041. begin
  1042. with IntConstList.LockList do
  1043. try
  1044. for i := 0 to Count - 1 do
  1045. if TIntConst(Items[i]).IntegerType = AIntegerType then
  1046. exit(TIntConst(Items[i]).IntToIdentFn);
  1047. Result := nil;
  1048. finally
  1049. IntConstList.UnlockList;
  1050. end;
  1051. end;
  1052. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  1053. var
  1054. i: Integer;
  1055. begin
  1056. with IntConstList.LockList do
  1057. try
  1058. for i := 0 to Count - 1 do
  1059. with TIntConst(Items[I]) do
  1060. if TIntConst(Items[I]).IntegerType = AIntegerType then
  1061. exit(IdentToIntFn);
  1062. Result := nil;
  1063. finally
  1064. IntConstList.UnlockList;
  1065. end;
  1066. end;
  1067. function IdentToInt(const Ident: String; out Int: LongInt;
  1068. const Map: array of TIdentMapEntry): Boolean;
  1069. var
  1070. i: Integer;
  1071. begin
  1072. for i := Low(Map) to High(Map) do
  1073. if CompareText(Map[i].Name, Ident) = 0 then
  1074. begin
  1075. Int := Map[i].Value;
  1076. exit(True);
  1077. end;
  1078. Result := False;
  1079. end;
  1080. function IntToIdent(Int: LongInt; var Ident: String;
  1081. const Map: array of TIdentMapEntry): Boolean;
  1082. var
  1083. i: Integer;
  1084. begin
  1085. for i := Low(Map) to High(Map) do
  1086. if Map[i].Value = Int then
  1087. begin
  1088. Ident := Map[i].Name;
  1089. exit(True);
  1090. end;
  1091. Result := False;
  1092. end;
  1093. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  1094. var
  1095. i : Integer;
  1096. begin
  1097. with IntConstList.LockList do
  1098. try
  1099. for i := 0 to Count - 1 do
  1100. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  1101. Exit(True);
  1102. Result := false;
  1103. finally
  1104. IntConstList.UnlockList;
  1105. end;
  1106. end;
  1107. { TPropFixup }
  1108. // Tainted. TPropFixup is being removed.
  1109. Type
  1110. TInitHandler = Class(TObject)
  1111. AHandler : TInitComponentHandler;
  1112. AClass : TComponentClass;
  1113. end;
  1114. {$ifndef i8086}
  1115. type
  1116. TCodePtrList = TList;
  1117. {$endif i8086}
  1118. Var
  1119. InitHandlerList : TList;
  1120. FindGlobalComponentList : TCodePtrList;
  1121. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  1122. begin
  1123. if not(assigned(FindGlobalComponentList)) then
  1124. FindGlobalComponentList:=TCodePtrList.Create;
  1125. if FindGlobalComponentList.IndexOf(CodePointer(AFindGlobalComponent))<0 then
  1126. FindGlobalComponentList.Add(CodePointer(AFindGlobalComponent));
  1127. end;
  1128. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  1129. begin
  1130. if assigned(FindGlobalComponentList) then
  1131. FindGlobalComponentList.Remove(CodePointer(AFindGlobalComponent));
  1132. end;
  1133. function FindGlobalComponent(const Name: string): TComponent;
  1134. var
  1135. i : sizeint;
  1136. begin
  1137. FindGlobalComponent:=nil;
  1138. if assigned(FindGlobalComponentList) then
  1139. begin
  1140. for i:=FindGlobalComponentList.Count-1 downto 0 do
  1141. begin
  1142. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  1143. if assigned(FindGlobalComponent) then
  1144. break;
  1145. end;
  1146. end;
  1147. end;
  1148. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  1149. Var
  1150. I : Integer;
  1151. H: TInitHandler;
  1152. begin
  1153. If (InitHandlerList=Nil) then
  1154. InitHandlerList:=TList.Create;
  1155. H:=TInitHandler.Create;
  1156. H.Aclass:=ComponentClass;
  1157. H.AHandler:=Handler;
  1158. try
  1159. With InitHandlerList do
  1160. begin
  1161. I:=0;
  1162. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  1163. Inc(I);
  1164. { override? }
  1165. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  1166. begin
  1167. TInitHandler(Items[I]).AHandler:=Handler;
  1168. H.Free;
  1169. end
  1170. else
  1171. InitHandlerList.Insert(I,H);
  1172. end;
  1173. except
  1174. H.Free;
  1175. raise;
  1176. end;
  1177. end;
  1178. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  1179. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  1180. var
  1181. ResStream : TResourceStream;
  1182. ResID : TFPResourceHandle;
  1183. begin
  1184. if Inst=0 then
  1185. Inst:=HInstance;
  1186. ResId:=FindResource(Inst, Res, RT_RCDATA);
  1187. result:=ResID<>0;
  1188. try
  1189. if Result then
  1190. begin
  1191. ResStream:=TResourceStream.CreateFromID(Inst,ResID,RT_RCDATA);
  1192. try
  1193. Component:=ResStream.ReadComponent(Component);
  1194. finally
  1195. ResStream.Free;
  1196. end;
  1197. end;
  1198. except
  1199. on EResNotFound do
  1200. result:=false;
  1201. end;
  1202. end;
  1203. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  1204. function doinit(_class : TClass) : boolean;
  1205. begin
  1206. result:=false;
  1207. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  1208. exit;
  1209. result:=doinit(_class.ClassParent);
  1210. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  1211. end;
  1212. begin
  1213. {$ifdef FPC_HAS_FEATURE_THREADING}
  1214. GlobalNameSpace.BeginWrite;
  1215. try
  1216. {$endif}
  1217. result:=doinit(Instance.ClassType);
  1218. {$ifdef FPC_HAS_FEATURE_THREADING}
  1219. finally
  1220. GlobalNameSpace.EndWrite;
  1221. end;
  1222. {$endif}
  1223. end;
  1224. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  1225. Var
  1226. I : Integer;
  1227. begin
  1228. I:=0;
  1229. if not Assigned(InitHandlerList) then begin
  1230. Result := True;
  1231. Exit;
  1232. end;
  1233. Result:=False;
  1234. With InitHandlerList do
  1235. begin
  1236. I:=0;
  1237. // Instance is the normally the lowest one, so that one should be used when searching.
  1238. While Not result and (I<Count) do
  1239. begin
  1240. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  1241. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  1242. Inc(I);
  1243. end;
  1244. end;
  1245. end;
  1246. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  1247. begin
  1248. Result:=ReadComponentRes(ResName,Instance)=Instance;
  1249. end;
  1250. function SysReadComponentRes(HInstance : THandle; const ResName: String; Instance: TComponent): TComponent;
  1251. Var
  1252. H : TFPResourceHandle;
  1253. begin
  1254. { Windows unit also has a FindResource function, use the one from
  1255. system unit here. }
  1256. H:=system.FindResource(HInstance,ResName,RT_RCDATA);
  1257. if (PtrInt(H)=0) then
  1258. Result:=Nil
  1259. else
  1260. With TResourceStream.Create(HInstance,ResName,RT_RCDATA) do
  1261. try
  1262. Result:=ReadComponent(Instance);
  1263. Finally
  1264. Free;
  1265. end;
  1266. end;
  1267. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  1268. begin
  1269. Result:=SysReadComponentRes(Hinstance,Resname,Instance);
  1270. end;
  1271. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  1272. begin
  1273. Result:=SysReadComponentRes(Hinstance,ResName,Nil);
  1274. end;
  1275. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  1276. var
  1277. FileStream: TStream;
  1278. begin
  1279. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  1280. try
  1281. Result := FileStream.ReadComponentRes(Instance);
  1282. finally
  1283. FileStream.Free;
  1284. end;
  1285. end;
  1286. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  1287. var
  1288. FileStream: TStream;
  1289. begin
  1290. FileStream := TFileStream.Create(FileName, fmCreate);
  1291. try
  1292. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  1293. finally
  1294. FileStream.Free;
  1295. end;
  1296. end;
  1297. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  1298. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  1299. Var
  1300. P : Integer;
  1301. CM : Boolean;
  1302. begin
  1303. P:=Pos('.',APath);
  1304. CM:=False;
  1305. If (P=0) then
  1306. begin
  1307. If CStyle then
  1308. begin
  1309. P:=Pos('->',APath);
  1310. CM:=P<>0;
  1311. end;
  1312. If (P=0) Then
  1313. P:=Length(APath)+1;
  1314. end;
  1315. Result:=Copy(APath,1,P-1);
  1316. Delete(APath,1,P+Ord(CM));
  1317. end;
  1318. Var
  1319. C : TComponent;
  1320. S : String;
  1321. begin
  1322. If (APath='') then
  1323. Result:=Nil
  1324. else
  1325. begin
  1326. Result:=Root;
  1327. While (APath<>'') And (Result<>Nil) do
  1328. begin
  1329. C:=Result;
  1330. S:=Uppercase(GetNextName);
  1331. Result:=C.FindComponent(S);
  1332. If (Result=Nil) And (S='OWNER') then
  1333. Result:=C;
  1334. end;
  1335. end;
  1336. end;
  1337. {$ifdef FPC_HAS_FEATURE_THREADING}
  1338. threadvar
  1339. {$else}
  1340. var
  1341. {$endif}
  1342. GlobalLoaded, GlobalLists: TFpList;
  1343. procedure BeginGlobalLoading;
  1344. begin
  1345. if not Assigned(GlobalLists) then
  1346. GlobalLists := TFpList.Create;
  1347. GlobalLists.Add(GlobalLoaded);
  1348. GlobalLoaded := TFpList.Create;
  1349. end;
  1350. { Notify all global components that they have been loaded completely }
  1351. procedure NotifyGlobalLoading;
  1352. var
  1353. i: Integer;
  1354. begin
  1355. for i := 0 to GlobalLoaded.Count - 1 do
  1356. TComponent(GlobalLoaded[i]).Loaded;
  1357. end;
  1358. procedure EndGlobalLoading;
  1359. begin
  1360. { Free the memory occupied by BeginGlobalLoading }
  1361. GlobalLoaded.Free;
  1362. GlobalLoaded := TFpList(GlobalLists.Last);
  1363. GlobalLists.Delete(GlobalLists.Count - 1);
  1364. if GlobalLists.Count = 0 then
  1365. begin
  1366. GlobalLists.Free;
  1367. GlobalLists := nil;
  1368. end;
  1369. end;
  1370. function CollectionsEqual(C1, C2: TCollection): Boolean;
  1371. begin
  1372. // !!!: Implement this
  1373. CollectionsEqual:=false;
  1374. end;
  1375. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  1376. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  1377. var
  1378. w : twriter;
  1379. begin
  1380. w:=twriter.create(s,4096);
  1381. try
  1382. w.root:=o;
  1383. w.flookuproot:=o;
  1384. w.writecollection(c);
  1385. finally
  1386. w.free;
  1387. end;
  1388. end;
  1389. var
  1390. s1,s2 : tmemorystream;
  1391. begin
  1392. result:=false;
  1393. if (c1.classtype<>c2.classtype) or
  1394. (c1.count<>c2.count) then
  1395. exit;
  1396. if c1.count = 0 then
  1397. begin
  1398. result:= true;
  1399. exit;
  1400. end;
  1401. s1:=tmemorystream.create;
  1402. try
  1403. s2:=tmemorystream.create;
  1404. try
  1405. stream_collection(s1,c1,owner1);
  1406. stream_collection(s2,c2,owner2);
  1407. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  1408. finally
  1409. s2.free;
  1410. end;
  1411. finally
  1412. s1.free;
  1413. end;
  1414. end;
  1415. { Object conversion routines }
  1416. type
  1417. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  1418. function CharToOrd(var P: Pointer): Cardinal;
  1419. begin
  1420. result:= ord(pchar(P)^);
  1421. inc(pchar(P));
  1422. end;
  1423. function WideCharToOrd(var P: Pointer): Cardinal;
  1424. begin
  1425. result:= ord(pwidechar(P)^);
  1426. inc(pwidechar(P));
  1427. end;
  1428. function Utf8ToOrd(var P:Pointer): Cardinal;
  1429. begin
  1430. // Should also check for illegal utf8 combinations
  1431. Result := Ord(PChar(P)^);
  1432. Inc(P);
  1433. if (Result and $80) <> 0 then
  1434. if (Ord(Result) and %11100000) = %11000000 then begin
  1435. Result := ((Result and %00011111) shl 6)
  1436. or (ord(PChar(P)^) and %00111111);
  1437. Inc(P);
  1438. end else if (Ord(Result) and %11110000) = %11100000 then begin
  1439. Result := ((Result and %00011111) shl 12)
  1440. or ((ord(PChar(P)^) and %00111111) shl 6)
  1441. or (ord((PChar(P)+1)^) and %00111111);
  1442. Inc(P,2);
  1443. end else begin
  1444. Result := ((ord(Result) and %00011111) shl 18)
  1445. or ((ord(PChar(P)^) and %00111111) shl 12)
  1446. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  1447. or (ord((PChar(P)+2)^) and %00111111);
  1448. Inc(P,3);
  1449. end;
  1450. end;
  1451. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  1452. var
  1453. Version: TBinaryObjectReader.TBOVersion;
  1454. procedure OutStr(s: String);
  1455. begin
  1456. if Length(s) > 0 then
  1457. Output.Write(s[1], Length(s));
  1458. end;
  1459. procedure OutLn(s: String);
  1460. begin
  1461. OutStr(s + LineEnding);
  1462. end;
  1463. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  1464. UseBytes: boolean = false);
  1465. var
  1466. res, NewStr: String;
  1467. w: Cardinal;
  1468. InString, NewInString: Boolean;
  1469. begin
  1470. if p = nil then begin
  1471. res:= '''''';
  1472. end
  1473. else
  1474. begin
  1475. res := '';
  1476. InString := False;
  1477. while P < LastP do
  1478. begin
  1479. NewInString := InString;
  1480. w := CharToOrdfunc(P);
  1481. if w = ord('''') then
  1482. begin //quote char
  1483. if not InString then
  1484. NewInString := True;
  1485. NewStr := '''''';
  1486. end
  1487. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  1488. begin //printable ascii or bytes
  1489. if not InString then
  1490. NewInString := True;
  1491. NewStr := char(w);
  1492. end
  1493. else
  1494. begin //ascii control chars, non ascii
  1495. if InString then
  1496. NewInString := False;
  1497. NewStr := '#' + IntToStr(w);
  1498. end;
  1499. if NewInString <> InString then
  1500. begin
  1501. NewStr := '''' + NewStr;
  1502. InString := NewInString;
  1503. end;
  1504. res := res + NewStr;
  1505. end;
  1506. if InString then
  1507. res := res + '''';
  1508. end;
  1509. OutStr(res);
  1510. end;
  1511. procedure OutString(s: String);
  1512. begin
  1513. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  1514. end;
  1515. procedure OutWString(W: WideString);
  1516. begin
  1517. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1518. end;
  1519. procedure OutUString(W: UnicodeString);
  1520. begin
  1521. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1522. end;
  1523. procedure OutUtf8Str(s: String);
  1524. begin
  1525. if Encoding=oteLFM then
  1526. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
  1527. else
  1528. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  1529. end;
  1530. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1531. begin
  1532. Result:=Input.ReadWord;
  1533. Result:=LEtoN(Result);
  1534. end;
  1535. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1536. begin
  1537. Result:=Input.ReadDWord;
  1538. Result:=LEtoN(Result);
  1539. end;
  1540. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1541. begin
  1542. Input.ReadBuffer(Result,sizeof(Result));
  1543. Result:=LEtoN(Result);
  1544. end;
  1545. {$ifndef FPUNONE}
  1546. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1547. function ExtendedToDouble(e : pointer) : double;
  1548. var mant : qword;
  1549. exp : smallint;
  1550. sign : boolean;
  1551. d : qword;
  1552. begin
  1553. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  1554. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  1555. mant:=LEtoN(mant);
  1556. exp:=LetoN(word(exp));
  1557. sign:=(exp and $8000)<>0;
  1558. if sign then exp:=exp and $7FFF;
  1559. case exp of
  1560. 0 : mant:=0; //if denormalized, value is too small for double,
  1561. //so it's always zero
  1562. $7FFF : exp:=2047 //either infinity or NaN
  1563. else
  1564. begin
  1565. dec(exp,16383-1023);
  1566. if (exp>=-51) and (exp<=0) then //can be denormalized
  1567. begin
  1568. mant:=mant shr (-exp);
  1569. exp:=0;
  1570. end
  1571. else
  1572. if (exp<-51) or (exp>2046) then //exponent too large.
  1573. begin
  1574. Result:=0;
  1575. exit;
  1576. end
  1577. else //normalized value
  1578. mant:=mant shl 1; //hide most significant bit
  1579. end;
  1580. end;
  1581. d:=word(exp);
  1582. d:=d shl 52;
  1583. mant:=mant shr 12;
  1584. d:=d or mant;
  1585. if sign then d:=d or $8000000000000000;
  1586. Result:=pdouble(@d)^;
  1587. end;
  1588. {$ENDIF}
  1589. {$endif}
  1590. function ReadInt(ValueType: TValueType): Int64;
  1591. begin
  1592. case ValueType of
  1593. vaInt8: Result := ShortInt(Input.ReadByte);
  1594. vaInt16: Result := SmallInt(ReadWord);
  1595. vaInt32: Result := LongInt(ReadDWord);
  1596. vaInt64: Result := Int64(ReadQWord);
  1597. end;
  1598. end;
  1599. function ReadInt: Int64;
  1600. begin
  1601. Result := ReadInt(TValueType(Input.ReadByte));
  1602. end;
  1603. {$ifndef FPUNONE}
  1604. function ReadExtended : extended;
  1605. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1606. var ext : array[0..9] of byte;
  1607. {$ENDIF}
  1608. begin
  1609. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1610. Input.ReadBuffer(ext[0],10);
  1611. Result:=ExtendedToDouble(@(ext[0]));
  1612. {$ELSE}
  1613. Input.ReadBuffer(Result,sizeof(Result));
  1614. {$ENDIF}
  1615. end;
  1616. {$endif}
  1617. function ReadSStr: String;
  1618. var
  1619. len: Byte;
  1620. begin
  1621. len := Input.ReadByte;
  1622. SetLength(Result, len);
  1623. if (len > 0) then
  1624. Input.ReadBuffer(Result[1], len);
  1625. end;
  1626. function ReadLStr: String;
  1627. var
  1628. len: DWord;
  1629. begin
  1630. len := ReadDWord;
  1631. SetLength(Result, len);
  1632. if (len > 0) then
  1633. Input.ReadBuffer(Result[1], len);
  1634. end;
  1635. function ReadWStr: WideString;
  1636. var
  1637. len: DWord;
  1638. {$IFDEF ENDIAN_BIG}
  1639. i : integer;
  1640. {$ENDIF}
  1641. begin
  1642. len := ReadDWord;
  1643. SetLength(Result, len);
  1644. if (len > 0) then
  1645. begin
  1646. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1647. {$IFDEF ENDIAN_BIG}
  1648. for i:=1 to len do
  1649. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1650. {$ENDIF}
  1651. end;
  1652. end;
  1653. function ReadUStr: UnicodeString;
  1654. var
  1655. len: DWord;
  1656. {$IFDEF ENDIAN_BIG}
  1657. i : integer;
  1658. {$ENDIF}
  1659. begin
  1660. len := ReadDWord;
  1661. SetLength(Result, len);
  1662. if (len > 0) then
  1663. begin
  1664. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1665. {$IFDEF ENDIAN_BIG}
  1666. for i:=1 to len do
  1667. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1668. {$ENDIF}
  1669. end;
  1670. end;
  1671. procedure ReadPropList(indent: String);
  1672. procedure ProcessValue(ValueType: TValueType; Indent: String);
  1673. procedure ProcessBinary;
  1674. var
  1675. ToDo, DoNow, i: LongInt;
  1676. lbuf: array[0..31] of Byte;
  1677. s: String;
  1678. begin
  1679. ToDo := ReadDWord;
  1680. OutLn('{');
  1681. while ToDo > 0 do begin
  1682. DoNow := ToDo;
  1683. if DoNow > 32 then DoNow := 32;
  1684. Dec(ToDo, DoNow);
  1685. s := Indent + ' ';
  1686. Input.ReadBuffer(lbuf, DoNow);
  1687. for i := 0 to DoNow - 1 do
  1688. s := s + IntToHex(lbuf[i], 2);
  1689. OutLn(s);
  1690. end;
  1691. OutLn(indent + '}');
  1692. end;
  1693. var
  1694. s: String;
  1695. { len: LongInt; }
  1696. IsFirst: Boolean;
  1697. {$ifndef FPUNONE}
  1698. ext: Extended;
  1699. {$endif}
  1700. begin
  1701. case ValueType of
  1702. vaList: begin
  1703. OutStr('(');
  1704. IsFirst := True;
  1705. while True do begin
  1706. ValueType := TValueType(Input.ReadByte);
  1707. if ValueType = vaNull then break;
  1708. if IsFirst then begin
  1709. OutLn('');
  1710. IsFirst := False;
  1711. end;
  1712. OutStr(Indent + ' ');
  1713. ProcessValue(ValueType, Indent + ' ');
  1714. end;
  1715. OutLn(Indent + ')');
  1716. end;
  1717. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  1718. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  1719. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  1720. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  1721. {$ifndef FPUNONE}
  1722. vaExtended: begin
  1723. ext:=ReadExtended;
  1724. Str(ext,S);// Do not use localized strings.
  1725. OutLn(S);
  1726. end;
  1727. {$endif}
  1728. vaString: begin
  1729. OutString(ReadSStr);
  1730. OutLn('');
  1731. end;
  1732. vaIdent: OutLn(ReadSStr);
  1733. vaFalse: OutLn('False');
  1734. vaTrue: OutLn('True');
  1735. vaBinary: ProcessBinary;
  1736. vaSet: begin
  1737. OutStr('[');
  1738. IsFirst := True;
  1739. while True do begin
  1740. s := ReadSStr;
  1741. if Length(s) = 0 then break;
  1742. if not IsFirst then OutStr(', ');
  1743. IsFirst := False;
  1744. OutStr(s);
  1745. end;
  1746. OutLn(']');
  1747. end;
  1748. vaLString:
  1749. begin
  1750. OutString(ReadLStr);
  1751. OutLn('');
  1752. end;
  1753. vaWString:
  1754. begin
  1755. OutWString(ReadWStr);
  1756. OutLn('');
  1757. end;
  1758. vaUString:
  1759. begin
  1760. OutWString(ReadWStr);
  1761. OutLn('');
  1762. end;
  1763. vaNil:
  1764. OutLn('nil');
  1765. vaCollection: begin
  1766. OutStr('<');
  1767. while Input.ReadByte <> 0 do begin
  1768. OutLn(Indent);
  1769. Input.Seek(-1, soFromCurrent);
  1770. OutStr(indent + ' item');
  1771. ValueType := TValueType(Input.ReadByte);
  1772. if ValueType <> vaList then
  1773. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1774. OutLn('');
  1775. ReadPropList(indent + ' ');
  1776. OutStr(indent + ' end');
  1777. end;
  1778. OutLn('>');
  1779. end;
  1780. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1781. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1782. vaDate: begin OutLn('!!Date!!'); exit end;}
  1783. vaUTF8String: begin
  1784. OutUtf8Str(ReadLStr);
  1785. OutLn('');
  1786. end;
  1787. else
  1788. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1789. end;
  1790. end;
  1791. begin
  1792. while Input.ReadByte <> 0 do begin
  1793. Input.Seek(-1, soFromCurrent);
  1794. OutStr(indent + ReadSStr + ' = ');
  1795. ProcessValue(TValueType(Input.ReadByte), Indent);
  1796. end;
  1797. end;
  1798. procedure ReadObject(indent: String);
  1799. var
  1800. b: Byte;
  1801. ObjUnitName, ObjClassName, ObjName: String;
  1802. ChildPos: LongInt;
  1803. ValueType: TValueType;
  1804. p: SizeInt;
  1805. begin
  1806. // Check for FilerFlags
  1807. b := Input.ReadByte;
  1808. if (b and $f0) = $f0 then begin
  1809. if (b and 2) <> 0 then ChildPos := ReadInt;
  1810. end else begin
  1811. b := 0;
  1812. Input.Seek(-1, soFromCurrent);
  1813. end;
  1814. ObjUnitName:='';
  1815. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  1816. begin
  1817. ValueType := TValueType(Input.ReadByte);
  1818. if ValueType=vaString then
  1819. ObjClassName := ReadSStr
  1820. else
  1821. ObjClassName := ReadLStr;
  1822. p:=Pos(TBinaryObjectReader.UnitnameSeparator,ObjClassName);
  1823. if p>0 then
  1824. begin
  1825. ObjUnitName:=copy(ObjClassName,1,p-1);
  1826. System.Delete(ObjClassName,1,p);
  1827. end;
  1828. end else
  1829. ObjClassName := ReadSStr;
  1830. ObjName := ReadSStr;
  1831. OutStr(Indent);
  1832. if (b and 1) <> 0 then
  1833. OutStr('inherited')
  1834. else if (b and 4) <> 0 then
  1835. OutStr('inline')
  1836. else
  1837. OutStr('object');
  1838. OutStr(' ');
  1839. if ObjName <> '' then
  1840. OutStr(ObjName + ': ');
  1841. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  1842. begin
  1843. OutStr(ObjUnitName);
  1844. OutStr('/');
  1845. end;
  1846. OutStr(ObjClassName);
  1847. if (b and 2) <> 0 then
  1848. OutStr('[' + IntToStr(ChildPos) + ']');
  1849. OutLn('');
  1850. ReadPropList(indent + ' ');
  1851. while Input.ReadByte <> 0 do begin
  1852. Input.Seek(-1, soFromCurrent);
  1853. ReadObject(indent + ' ');
  1854. end;
  1855. OutLn(indent + 'end');
  1856. end;
  1857. var
  1858. Signature: DWord;
  1859. begin
  1860. Signature:=Input.ReadDWord;
  1861. if Signature = DWord(unaligned(FilerSignature1)) then
  1862. Version:=TBinaryObjectReader.TBOVersion.boVersion1
  1863. else if Signature = DWord(unaligned(FilerSignature)) then
  1864. Version:=TBinaryObjectReader.TBOVersion.boVersion0
  1865. else
  1866. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1867. ReadObject('');
  1868. end;
  1869. procedure ObjectBinaryToText(Input, Output: TStream);
  1870. begin
  1871. ObjectBinaryToText(Input,Output,oteDFM);
  1872. end;
  1873. procedure ObjectTextToBinary(Input, Output: TStream);
  1874. var
  1875. parser: TParser;
  1876. Version: TBinaryObjectReader.TBOVersion;
  1877. StartPos: Int64;
  1878. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1879. begin
  1880. w:=NtoLE(w);
  1881. Output.WriteWord(w);
  1882. end;
  1883. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1884. begin
  1885. lw:=NtoLE(lw);
  1886. Output.WriteDWord(lw);
  1887. end;
  1888. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1889. begin
  1890. qw:=NtoLE(qw);
  1891. Output.WriteBuffer(qw,sizeof(qword));
  1892. end;
  1893. {$ifndef FPUNONE}
  1894. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1895. procedure DoubleToExtended(d : double; e : pointer);
  1896. var mant : qword;
  1897. exp : smallint;
  1898. sign : boolean;
  1899. begin
  1900. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1901. exp :=(qword(d) shr 52) and $7FF;
  1902. sign:=(qword(d) and $8000000000000000)<>0;
  1903. case exp of
  1904. 0 : begin
  1905. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1906. begin
  1907. exp:=16383-1022;
  1908. while (mant and $8000000000000000)=0 do
  1909. begin
  1910. dec(exp);
  1911. mant:=mant shl 1;
  1912. end;
  1913. dec(exp); //don't shift, most significant bit is not hidden in extended
  1914. end;
  1915. end;
  1916. 2047 : exp:=$7FFF //either infinity or NaN
  1917. else
  1918. begin
  1919. inc(exp,16383-1023);
  1920. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1921. end;
  1922. end;
  1923. if sign then exp:=exp or $8000;
  1924. mant:=NtoLE(mant);
  1925. exp:=NtoLE(word(exp));
  1926. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1927. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1928. end;
  1929. {$ENDIF}
  1930. procedure WriteExtended(const e : extended);
  1931. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1932. var ext : array[0..9] of byte;
  1933. {$ENDIF}
  1934. begin
  1935. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1936. DoubleToExtended(e,@(ext[0]));
  1937. Output.WriteBuffer(ext[0],10);
  1938. {$ELSE}
  1939. Output.WriteBuffer(e,sizeof(e));
  1940. {$ENDIF}
  1941. end;
  1942. {$endif}
  1943. procedure WriteSString(const s: String);
  1944. var size : byte;
  1945. begin
  1946. if length(s)>255 then size:=255
  1947. else size:=length(s);
  1948. Output.WriteByte(size);
  1949. if Length(s) > 0 then
  1950. Output.WriteBuffer(s[1], size);
  1951. end;
  1952. procedure WriteLString(Const s: String);
  1953. begin
  1954. WriteDWord(Length(s));
  1955. if Length(s) > 0 then
  1956. Output.WriteBuffer(s[1], Length(s));
  1957. end;
  1958. procedure WriteSorLString(Const s: String);
  1959. begin
  1960. if length(s)<256 then
  1961. begin
  1962. Output.WriteByte(Ord(vaString));
  1963. WriteSString(s);
  1964. end else begin
  1965. Output.WriteByte(Ord(vaLString));
  1966. WriteSString(s);
  1967. end;
  1968. end;
  1969. procedure WriteWString(Const s: WideString);
  1970. var len : longword;
  1971. {$IFDEF ENDIAN_BIG}
  1972. i : integer;
  1973. ws : widestring;
  1974. {$ENDIF}
  1975. begin
  1976. len:=Length(s);
  1977. WriteDWord(len);
  1978. if len > 0 then
  1979. begin
  1980. {$IFDEF ENDIAN_BIG}
  1981. setlength(ws,len);
  1982. for i:=1 to len do
  1983. ws[i]:=widechar(SwapEndian(word(s[i])));
  1984. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1985. {$ELSE}
  1986. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1987. {$ENDIF}
  1988. end;
  1989. end;
  1990. procedure WriteInteger(value: Int64);
  1991. begin
  1992. if (value >= -128) and (value <= 127) then begin
  1993. Output.WriteByte(Ord(vaInt8));
  1994. Output.WriteByte(byte(value));
  1995. end else if (value >= -32768) and (value <= 32767) then begin
  1996. Output.WriteByte(Ord(vaInt16));
  1997. WriteWord(word(value));
  1998. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1999. Output.WriteByte(Ord(vaInt32));
  2000. WriteDWord(longword(value));
  2001. end else begin
  2002. Output.WriteByte(ord(vaInt64));
  2003. WriteQWord(qword(value));
  2004. end;
  2005. end;
  2006. procedure ProcessWideString(const left : widestring);
  2007. var ws : widestring;
  2008. begin
  2009. ws:=left+parser.TokenWideString;
  2010. while parser.NextToken = '+' do
  2011. begin
  2012. parser.NextToken; // Get next string fragment
  2013. if not (parser.Token in [toString,toWString]) then
  2014. parser.CheckToken(toWString);
  2015. ws:=ws+parser.TokenWideString;
  2016. end;
  2017. Output.WriteByte(Ord(vaWstring));
  2018. WriteWString(ws);
  2019. end;
  2020. procedure ProcessProperty; forward;
  2021. procedure ProcessValue;
  2022. var
  2023. {$ifndef FPUNONE}
  2024. flt: Extended;
  2025. {$endif}
  2026. s: String;
  2027. stream: TMemoryStream;
  2028. begin
  2029. case parser.Token of
  2030. toInteger:
  2031. begin
  2032. WriteInteger(parser.TokenInt);
  2033. parser.NextToken;
  2034. end;
  2035. {$ifndef FPUNONE}
  2036. toFloat:
  2037. begin
  2038. Output.WriteByte(Ord(vaExtended));
  2039. flt := Parser.TokenFloat;
  2040. WriteExtended(flt);
  2041. parser.NextToken;
  2042. end;
  2043. {$endif}
  2044. toString:
  2045. begin
  2046. s := parser.TokenString;
  2047. while parser.NextToken = '+' do
  2048. begin
  2049. parser.NextToken; // Get next string fragment
  2050. case parser.Token of
  2051. toString : s:=s+parser.TokenString;
  2052. toWString : begin
  2053. ProcessWideString(WideString(s));
  2054. exit;
  2055. end
  2056. else parser.CheckToken(toString);
  2057. end;
  2058. end;
  2059. if (length(S)>255) then
  2060. begin
  2061. Output.WriteByte(Ord(vaLString));
  2062. WriteLString(S);
  2063. end
  2064. else
  2065. begin
  2066. Output.WriteByte(Ord(vaString));
  2067. WriteSString(s);
  2068. end;
  2069. end;
  2070. toWString:
  2071. ProcessWideString('');
  2072. toSymbol:
  2073. begin
  2074. if CompareText(parser.TokenString, 'True') = 0 then
  2075. Output.WriteByte(Ord(vaTrue))
  2076. else if CompareText(parser.TokenString, 'False') = 0 then
  2077. Output.WriteByte(Ord(vaFalse))
  2078. else if CompareText(parser.TokenString, 'nil') = 0 then
  2079. Output.WriteByte(Ord(vaNil))
  2080. else
  2081. begin
  2082. Output.WriteByte(Ord(vaIdent));
  2083. WriteSString(parser.TokenComponentIdent);
  2084. end;
  2085. Parser.NextToken;
  2086. end;
  2087. // Set
  2088. '[':
  2089. begin
  2090. parser.NextToken;
  2091. Output.WriteByte(Ord(vaSet));
  2092. if parser.Token <> ']' then
  2093. while True do
  2094. begin
  2095. parser.CheckToken(toSymbol);
  2096. WriteSString(parser.TokenString);
  2097. parser.NextToken;
  2098. if parser.Token = ']' then
  2099. break;
  2100. parser.CheckToken(',');
  2101. parser.NextToken;
  2102. end;
  2103. Output.WriteByte(0);
  2104. parser.NextToken;
  2105. end;
  2106. // List
  2107. '(':
  2108. begin
  2109. parser.NextToken;
  2110. Output.WriteByte(Ord(vaList));
  2111. while parser.Token <> ')' do
  2112. ProcessValue;
  2113. Output.WriteByte(0);
  2114. parser.NextToken;
  2115. end;
  2116. // Collection
  2117. '<':
  2118. begin
  2119. parser.NextToken;
  2120. Output.WriteByte(Ord(vaCollection));
  2121. while parser.Token <> '>' do
  2122. begin
  2123. parser.CheckTokenSymbol('item');
  2124. parser.NextToken;
  2125. // ConvertOrder
  2126. Output.WriteByte(Ord(vaList));
  2127. while not parser.TokenSymbolIs('end') do
  2128. ProcessProperty;
  2129. parser.NextToken; // Skip 'end'
  2130. Output.WriteByte(0);
  2131. end;
  2132. Output.WriteByte(0);
  2133. parser.NextToken;
  2134. end;
  2135. // Binary data
  2136. '{':
  2137. begin
  2138. Output.WriteByte(Ord(vaBinary));
  2139. stream := TMemoryStream.Create;
  2140. try
  2141. parser.HexToBinary(stream);
  2142. WriteDWord(stream.Size);
  2143. Output.WriteBuffer(Stream.Memory^, stream.Size);
  2144. finally
  2145. stream.Free;
  2146. end;
  2147. parser.NextToken;
  2148. end;
  2149. else
  2150. parser.Error(SInvalidProperty);
  2151. end;
  2152. end;
  2153. procedure ProcessProperty;
  2154. var
  2155. name: String;
  2156. begin
  2157. // Get name of property
  2158. parser.CheckToken(toSymbol);
  2159. name := parser.TokenString;
  2160. while True do begin
  2161. parser.NextToken;
  2162. if parser.Token <> '.' then break;
  2163. parser.NextToken;
  2164. parser.CheckToken(toSymbol);
  2165. name := name + '.' + parser.TokenString;
  2166. end;
  2167. WriteSString(name);
  2168. parser.CheckToken('=');
  2169. parser.NextToken;
  2170. ProcessValue;
  2171. end;
  2172. procedure ProcessObject(Root: boolean);
  2173. var
  2174. Flags: Byte;
  2175. ObjectName, ObjUnitName, ObjClassName: String;
  2176. ChildPos: Integer;
  2177. begin
  2178. if parser.TokenSymbolIs('OBJECT') then
  2179. Flags :=0 { IsInherited := False }
  2180. else begin
  2181. if parser.TokenSymbolIs('INHERITED') then
  2182. Flags := 1 { IsInherited := True; }
  2183. else begin
  2184. parser.CheckTokenSymbol('INLINE');
  2185. Flags := 4;
  2186. end;
  2187. end;
  2188. parser.NextToken;
  2189. parser.CheckToken(toSymbol);
  2190. ObjectName := '';
  2191. ObjUnitName := '';
  2192. ObjClassName := parser.TokenString;
  2193. parser.NextToken;
  2194. if parser.Token = '/' then begin
  2195. ObjUnitName := ObjClassName;
  2196. parser.NextToken;
  2197. parser.CheckToken(toSymbol);
  2198. ObjClassName := parser.TokenString;
  2199. parser.NextToken;
  2200. end else if parser.Token = ':' then begin
  2201. parser.NextToken;
  2202. parser.CheckToken(toSymbol);
  2203. ObjectName := ObjClassName;
  2204. ObjClassName := parser.TokenString;
  2205. parser.NextToken;
  2206. if parser.Token = '/' then begin
  2207. ObjUnitName := ObjClassName;
  2208. parser.NextToken;
  2209. parser.CheckToken(toSymbol);
  2210. ObjClassName := parser.TokenString;
  2211. parser.NextToken;
  2212. end;
  2213. if parser.Token = '[' then begin
  2214. parser.NextToken;
  2215. ChildPos := parser.TokenInt;
  2216. parser.NextToken;
  2217. parser.CheckToken(']');
  2218. parser.NextToken;
  2219. Flags := Flags or 2;
  2220. end;
  2221. end;
  2222. if Root then
  2223. begin
  2224. if (ObjUnitName<>'') then
  2225. Version:=TBinaryObjectReader.TBOVersion.boVersion1;
  2226. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  2227. Output.WriteBuffer(FilerSignature1[1], length(FilerSignature1))
  2228. else
  2229. Output.WriteBuffer(FilerSignature[1], length(FilerSignature));
  2230. end;
  2231. if Flags <> 0 then begin
  2232. Output.WriteByte($f0 or Flags);
  2233. if (Flags and 2) <> 0 then
  2234. WriteInteger(ChildPos);
  2235. end;
  2236. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  2237. WriteSorLString(ObjUnitName+TBinaryObjectReader.UnitnameSeparator+ObjClassName)
  2238. else
  2239. WriteSString(ObjClassName);
  2240. WriteSString(ObjectName);
  2241. // Convert property list
  2242. while not (parser.TokenSymbolIs('END') or
  2243. parser.TokenSymbolIs('OBJECT') or
  2244. parser.TokenSymbolIs('INHERITED') or
  2245. parser.TokenSymbolIs('INLINE')) do
  2246. ProcessProperty;
  2247. Output.WriteByte(0); // Terminate property list
  2248. // Convert child objects
  2249. while not parser.TokenSymbolIs('END') do ProcessObject(false);
  2250. parser.NextToken; // Skip end token
  2251. Output.WriteByte(0); // Terminate property list
  2252. end;
  2253. begin
  2254. Version:=TBinaryObjectReader.TBOVersion.boVersion0;
  2255. parser := TParser.Create(Input);
  2256. try
  2257. StartPos:=Output.Position;
  2258. ProcessObject(true);
  2259. finally
  2260. parser.Free;
  2261. end;
  2262. end;
  2263. procedure ObjectResourceToText(Input, Output: TStream);
  2264. begin
  2265. Input.ReadResHeader;
  2266. ObjectBinaryToText(Input, Output);
  2267. end;
  2268. procedure ObjectTextToResource(Input, Output: TStream);
  2269. var
  2270. StartPos, FixupInfo: LongInt;
  2271. parser: TParser;
  2272. name: String;
  2273. begin
  2274. // Get form type name
  2275. StartPos := Input.Position;
  2276. parser := TParser.Create(Input);
  2277. try
  2278. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  2279. parser.NextToken;
  2280. parser.CheckToken(toSymbol);
  2281. parser.NextToken;
  2282. parser.CheckToken(':');
  2283. parser.NextToken;
  2284. parser.CheckToken(toSymbol);
  2285. name := parser.TokenString;
  2286. finally
  2287. parser.Free;
  2288. Input.Position := StartPos;
  2289. end;
  2290. name := UpperCase(name);
  2291. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  2292. ObjectTextToBinary(Input, Output); // Convert the stuff!
  2293. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  2294. end;
  2295. { Utility routines }
  2296. Function IfThen(AValue: Boolean; const ATrue: TStringList; const AFalse: TStringList = nil): TStringList; overload;
  2297. begin
  2298. if avalue then
  2299. result:=atrue
  2300. else
  2301. result:=afalse;
  2302. end;
  2303. function LineStart(Buffer, BufPos: PChar): PChar;
  2304. begin
  2305. Result := BufPos;
  2306. while Result > Buffer do begin
  2307. Dec(Result);
  2308. if Result[0] = #10 then break;
  2309. end;
  2310. end;
  2311. procedure CommonInit;
  2312. begin
  2313. {$ifdef FPC_HAS_FEATURE_THREADING}
  2314. SynchronizeTimeoutEvent:=RtlEventCreate;
  2315. InterlockedIncrement(ThreadQueueLockCounter);
  2316. InitCriticalSection(ThreadQueueLock);
  2317. MainThreadID:=GetCurrentThreadID;
  2318. {$else}
  2319. MainThreadID:=0{GetCurrentThreadID};
  2320. {$endif}
  2321. ExternalThreads := TThreadList.Create;
  2322. {$ifdef FPC_HAS_FEATURE_THREADING}
  2323. InitCriticalsection(ResolveSection);
  2324. TThread.FProcessorCount := CPUCount;
  2325. {$else}
  2326. TThread.FProcessorCount := 1{CPUCount};
  2327. {$endif}
  2328. InitHandlerList:=Nil;
  2329. FindGlobalComponentList:=nil;
  2330. IntConstList := TThreadList.Create;
  2331. ClassList := TThreadList.Create;
  2332. ClassAliasList := nil;
  2333. { on unix this maps to a simple rw synchornizer }
  2334. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  2335. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  2336. end;
  2337. procedure CommonCleanup;
  2338. var
  2339. i: Integer;
  2340. tmpentry: TThread.PThreadQueueEntry;
  2341. begin
  2342. {$ifdef FPC_HAS_FEATURE_THREADING}
  2343. GlobalNameSpace.BeginWrite;
  2344. {$endif}
  2345. with IntConstList.LockList do
  2346. try
  2347. for i := 0 to Count - 1 do
  2348. TIntConst(Items[I]).Free;
  2349. finally
  2350. IntConstList.UnlockList;
  2351. end;
  2352. IntConstList.Free;
  2353. ClassList.Free;
  2354. ClassAliasList.Free;
  2355. RemoveFixupReferences(nil, '');
  2356. {$ifdef FPC_HAS_FEATURE_THREADING}
  2357. DoneCriticalsection(ResolveSection);
  2358. {$endif}
  2359. GlobalLists.Free;
  2360. ComponentPages.Free;
  2361. FreeAndNil(NeedResolving);
  2362. {$ifdef FPC_HAS_FEATURE_THREADING}
  2363. GlobalNameSpace.EndWrite;
  2364. {$endif}
  2365. { GlobalNameSpace is an interface so this is enough }
  2366. GlobalNameSpace:=nil;
  2367. if (InitHandlerList<>Nil) then
  2368. for i := 0 to InitHandlerList.Count - 1 do
  2369. TInitHandler(InitHandlerList.Items[I]).Free;
  2370. InitHandlerList.Free;
  2371. InitHandlerList:=Nil;
  2372. FindGlobalComponentList.Free;
  2373. FindGlobalComponentList:=nil;
  2374. ExternalThreadsCleanup:=True;
  2375. with ExternalThreads.LockList do
  2376. try
  2377. for i := 0 to Count - 1 do
  2378. TThread(Items[i]).Free;
  2379. finally
  2380. ExternalThreads.UnlockList;
  2381. end;
  2382. FreeAndNil(ExternalThreads);
  2383. {$ifdef FPC_HAS_FEATURE_THREADING}
  2384. RtlEventDestroy(SynchronizeTimeoutEvent);
  2385. try
  2386. System.EnterCriticalSection(ThreadQueueLock);
  2387. {$endif}
  2388. { clean up the queue, but keep in mind that the entries used for Synchronize
  2389. are owned by the corresponding TThread }
  2390. while Assigned(ThreadQueueHead) do begin
  2391. tmpentry := ThreadQueueHead;
  2392. ThreadQueueHead := tmpentry^.Next;
  2393. if not Assigned(tmpentry^.SyncEvent) then
  2394. Dispose(tmpentry);
  2395. end;
  2396. { We also need to reset ThreadQueueTail }
  2397. ThreadQueueTail := nil;
  2398. {$ifdef FPC_HAS_FEATURE_THREADING}
  2399. finally
  2400. System.LeaveCriticalSection(ThreadQueueLock);
  2401. end;
  2402. if InterlockedDecrement(ThreadQueueLockCounter)=0 then
  2403. DoneCriticalSection(ThreadQueueLock);
  2404. {$endif}
  2405. end;
  2406. { TFiler implementation }
  2407. {$i filer.inc}
  2408. { TReader implementation }
  2409. {$i reader.inc}
  2410. { TWriter implementations }
  2411. {$i writer.inc}
  2412. {$i twriter.inc}