classes.inc 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178
  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; AddEmptyStrings : Boolean = False): 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) or AddEmptyStrings then
  523. begin
  524. if assigned(Strings) then
  525. begin
  526. setlength(s, l);
  527. if l>0 then
  528. move (b^, s[1],l*SizeOf(char));
  529. Strings.Add (s);
  530. end;
  531. inc (result);
  532. end;
  533. end;
  534. var
  535. quoted : char;
  536. begin
  537. result := 0;
  538. c := Content;
  539. Quoted := #0;
  540. Separators := Separators + [#13, #10] - ['''','"'];
  541. SkipWhitespace;
  542. b := c;
  543. while (c^ <> #0) do
  544. begin
  545. if (c^ = Quoted) then
  546. begin
  547. if ((c+1)^ = Quoted) then
  548. inc (c)
  549. else
  550. Quoted := #0
  551. end
  552. else if (Quoted = #0) and (c^ in ['''','"']) then
  553. Quoted := c^;
  554. if (Quoted = #0) and (c^ in Separators) then
  555. begin
  556. AddString;
  557. inc (c);
  558. SkipWhitespace;
  559. b := c;
  560. end
  561. else
  562. inc (c);
  563. end;
  564. if (c <> b) then
  565. AddString;
  566. end;
  567. { Point and rectangle constructors }
  568. function Point(AX, AY: Integer): TPoint;
  569. begin
  570. with Result do
  571. begin
  572. X := AX;
  573. Y := AY;
  574. end;
  575. end;
  576. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  577. begin
  578. with Result do
  579. begin
  580. X := AX;
  581. Y := AY;
  582. end;
  583. end;
  584. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  585. begin
  586. with Result do
  587. begin
  588. Left := ALeft;
  589. Top := ATop;
  590. Right := ARight;
  591. Bottom := ABottom;
  592. end;
  593. end;
  594. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  595. begin
  596. with Result do
  597. begin
  598. Left := ALeft;
  599. Top := ATop;
  600. Right := ALeft + AWidth;
  601. Bottom := ATop + AHeight;
  602. end;
  603. end;
  604. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  605. begin
  606. { lazy, but should work }
  607. result:=QWord(P1)=QWord(P2);
  608. end;
  609. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  610. begin
  611. { lazy, but should work }
  612. result:=DWord(P1)=DWord(P2);
  613. end;
  614. function InvalidPoint(X, Y: Integer): Boolean;
  615. begin
  616. result:=(X=-1) and (Y=-1);
  617. end;
  618. function InvalidPoint(const At: TPoint): Boolean;
  619. begin
  620. result:=(At.x=-1) and (At.y=-1);
  621. end;
  622. function InvalidPoint(const At: TSmallPoint): Boolean;
  623. begin
  624. result:=(At.x=-1) and (At.y=-1);
  625. end;
  626. { Object filing routines }
  627. var
  628. IntConstList: TThreadList;
  629. type
  630. TIntConst = class
  631. IntegerType: PTypeInfo; // The integer type RTTI pointer
  632. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  633. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  634. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  635. AIntToIdent: TIntToIdent);
  636. end;
  637. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  638. AIntToIdent: TIntToIdent);
  639. begin
  640. IntegerType := AIntegerType;
  641. IdentToIntFn := AIdentToInt;
  642. IntToIdentFn := AIntToIdent;
  643. end;
  644. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  645. IntToIdentFn: TIntToIdent);
  646. begin
  647. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  648. end;
  649. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  650. var
  651. i: Integer;
  652. begin
  653. with IntConstList.LockList do
  654. try
  655. for i := 0 to Count - 1 do
  656. if TIntConst(Items[i]).IntegerType = AIntegerType then
  657. exit(TIntConst(Items[i]).IntToIdentFn);
  658. Result := nil;
  659. finally
  660. IntConstList.UnlockList;
  661. end;
  662. end;
  663. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  664. var
  665. i: Integer;
  666. begin
  667. with IntConstList.LockList do
  668. try
  669. for i := 0 to Count - 1 do
  670. with TIntConst(Items[I]) do
  671. if TIntConst(Items[I]).IntegerType = AIntegerType then
  672. exit(IdentToIntFn);
  673. Result := nil;
  674. finally
  675. IntConstList.UnlockList;
  676. end;
  677. end;
  678. function IdentToInt(const Ident: String; var Int: LongInt;
  679. const Map: array of TIdentMapEntry): Boolean;
  680. var
  681. i: Integer;
  682. begin
  683. for i := Low(Map) to High(Map) do
  684. if CompareText(Map[i].Name, Ident) = 0 then
  685. begin
  686. Int := Map[i].Value;
  687. exit(True);
  688. end;
  689. Result := False;
  690. end;
  691. function IntToIdent(Int: LongInt; var Ident: String;
  692. const Map: array of TIdentMapEntry): Boolean;
  693. var
  694. i: Integer;
  695. begin
  696. for i := Low(Map) to High(Map) do
  697. if Map[i].Value = Int then
  698. begin
  699. Ident := Map[i].Name;
  700. exit(True);
  701. end;
  702. Result := False;
  703. end;
  704. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  705. var
  706. i : Integer;
  707. begin
  708. with IntConstList.LockList do
  709. try
  710. for i := 0 to Count - 1 do
  711. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  712. Exit(True);
  713. Result := false;
  714. finally
  715. IntConstList.UnlockList;
  716. end;
  717. end;
  718. { TPropFixup }
  719. // Tainted. TPropFixup is being removed.
  720. Type
  721. TInitHandler = Class(TObject)
  722. AHandler : TInitComponentHandler;
  723. AClass : TComponentClass;
  724. end;
  725. {$ifndef i8086}
  726. type
  727. TCodePtrList = TList;
  728. {$endif i8086}
  729. Var
  730. InitHandlerList : TList;
  731. FindGlobalComponentList : TCodePtrList;
  732. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  733. begin
  734. if not(assigned(FindGlobalComponentList)) then
  735. FindGlobalComponentList:=TCodePtrList.Create;
  736. if FindGlobalComponentList.IndexOf(CodePointer(AFindGlobalComponent))<0 then
  737. FindGlobalComponentList.Add(CodePointer(AFindGlobalComponent));
  738. end;
  739. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  740. begin
  741. if assigned(FindGlobalComponentList) then
  742. FindGlobalComponentList.Remove(CodePointer(AFindGlobalComponent));
  743. end;
  744. function FindGlobalComponent(const Name: string): TComponent;
  745. var
  746. i : sizeint;
  747. begin
  748. FindGlobalComponent:=nil;
  749. if assigned(FindGlobalComponentList) then
  750. begin
  751. for i:=FindGlobalComponentList.Count-1 downto 0 do
  752. begin
  753. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  754. if assigned(FindGlobalComponent) then
  755. break;
  756. end;
  757. end;
  758. end;
  759. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  760. Var
  761. I : Integer;
  762. H: TInitHandler;
  763. begin
  764. If (InitHandlerList=Nil) then
  765. InitHandlerList:=TList.Create;
  766. H:=TInitHandler.Create;
  767. H.Aclass:=ComponentClass;
  768. H.AHandler:=Handler;
  769. try
  770. With InitHandlerList do
  771. begin
  772. I:=0;
  773. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  774. Inc(I);
  775. { override? }
  776. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  777. begin
  778. TInitHandler(Items[I]).AHandler:=Handler;
  779. H.Free;
  780. end
  781. else
  782. InitHandlerList.Insert(I,H);
  783. end;
  784. except
  785. H.Free;
  786. raise;
  787. end;
  788. end;
  789. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  790. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  791. var
  792. ResStream : TResourceStream;
  793. begin
  794. result:=true;
  795. if Inst=0 then
  796. Inst:=HInstance;
  797. try
  798. ResStream:=TResourceStream.Create(Inst,res,RT_RCDATA);
  799. try
  800. Component:=ResStream.ReadComponent(Component);
  801. finally
  802. ResStream.Free;
  803. end;
  804. except
  805. on EResNotFound do
  806. result:=false;
  807. end;
  808. end;
  809. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  810. function doinit(_class : TClass) : boolean;
  811. begin
  812. result:=false;
  813. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  814. exit;
  815. result:=doinit(_class.ClassParent);
  816. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  817. end;
  818. begin
  819. GlobalNameSpace.BeginWrite;
  820. try
  821. result:=doinit(Instance.ClassType);
  822. finally
  823. GlobalNameSpace.EndWrite;
  824. end;
  825. end;
  826. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  827. Var
  828. I : Integer;
  829. begin
  830. I:=0;
  831. if not Assigned(InitHandlerList) then begin
  832. Result := True;
  833. Exit;
  834. end;
  835. Result:=False;
  836. With InitHandlerList do
  837. begin
  838. I:=0;
  839. // Instance is the normally the lowest one, so that one should be used when searching.
  840. While Not result and (I<Count) do
  841. begin
  842. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  843. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  844. Inc(I);
  845. end;
  846. end;
  847. end;
  848. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  849. begin
  850. { !!!: Too Win32-specific }
  851. InitComponentRes := False;
  852. end;
  853. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  854. begin
  855. { !!!: Too Win32-specific }
  856. ReadComponentRes := nil;
  857. end;
  858. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  859. begin
  860. { !!!: Too Win32-specific in VCL }
  861. ReadComponentResEx := nil;
  862. end;
  863. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  864. var
  865. FileStream: TStream;
  866. begin
  867. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  868. try
  869. Result := FileStream.ReadComponentRes(Instance);
  870. finally
  871. FileStream.Free;
  872. end;
  873. end;
  874. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  875. var
  876. FileStream: TStream;
  877. begin
  878. FileStream := TFileStream.Create(FileName, fmCreate);
  879. try
  880. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  881. finally
  882. FileStream.Free;
  883. end;
  884. end;
  885. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  886. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  887. Var
  888. P : Integer;
  889. CM : Boolean;
  890. begin
  891. P:=Pos('.',APath);
  892. CM:=False;
  893. If (P=0) then
  894. begin
  895. If CStyle then
  896. begin
  897. P:=Pos('->',APath);
  898. CM:=P<>0;
  899. end;
  900. If (P=0) Then
  901. P:=Length(APath)+1;
  902. end;
  903. Result:=Copy(APath,1,P-1);
  904. Delete(APath,1,P+Ord(CM));
  905. end;
  906. Var
  907. C : TComponent;
  908. S : String;
  909. begin
  910. If (APath='') then
  911. Result:=Nil
  912. else
  913. begin
  914. Result:=Root;
  915. While (APath<>'') And (Result<>Nil) do
  916. begin
  917. C:=Result;
  918. S:=Uppercase(GetNextName);
  919. Result:=C.FindComponent(S);
  920. If (Result=Nil) And (S='OWNER') then
  921. Result:=C;
  922. end;
  923. end;
  924. end;
  925. threadvar
  926. GlobalLoaded, GlobalLists: TFpList;
  927. procedure BeginGlobalLoading;
  928. begin
  929. if not Assigned(GlobalLists) then
  930. GlobalLists := TFpList.Create;
  931. GlobalLists.Add(GlobalLoaded);
  932. GlobalLoaded := TFpList.Create;
  933. end;
  934. { Notify all global components that they have been loaded completely }
  935. procedure NotifyGlobalLoading;
  936. var
  937. i: Integer;
  938. begin
  939. for i := 0 to GlobalLoaded.Count - 1 do
  940. TComponent(GlobalLoaded[i]).Loaded;
  941. end;
  942. procedure EndGlobalLoading;
  943. begin
  944. { Free the memory occupied by BeginGlobalLoading }
  945. GlobalLoaded.Free;
  946. GlobalLoaded := TFpList(GlobalLists.Last);
  947. GlobalLists.Delete(GlobalLists.Count - 1);
  948. if GlobalLists.Count = 0 then
  949. begin
  950. GlobalLists.Free;
  951. GlobalLists := nil;
  952. end;
  953. end;
  954. function CollectionsEqual(C1, C2: TCollection): Boolean;
  955. begin
  956. // !!!: Implement this
  957. CollectionsEqual:=false;
  958. end;
  959. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  960. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  961. var
  962. w : twriter;
  963. begin
  964. w:=twriter.create(s,4096);
  965. try
  966. w.root:=o;
  967. w.flookuproot:=o;
  968. w.writecollection(c);
  969. finally
  970. w.free;
  971. end;
  972. end;
  973. var
  974. s1,s2 : tmemorystream;
  975. begin
  976. result:=false;
  977. if (c1.classtype<>c2.classtype) or
  978. (c1.count<>c2.count) then
  979. exit;
  980. if c1.count = 0 then
  981. begin
  982. result:= true;
  983. exit;
  984. end;
  985. s1:=tmemorystream.create;
  986. try
  987. s2:=tmemorystream.create;
  988. try
  989. stream_collection(s1,c1,owner1);
  990. stream_collection(s2,c2,owner2);
  991. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  992. finally
  993. s2.free;
  994. end;
  995. finally
  996. s1.free;
  997. end;
  998. end;
  999. { Object conversion routines }
  1000. type
  1001. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  1002. function CharToOrd(var P: Pointer): Cardinal;
  1003. begin
  1004. result:= ord(pchar(P)^);
  1005. inc(pchar(P));
  1006. end;
  1007. function WideCharToOrd(var P: Pointer): Cardinal;
  1008. begin
  1009. result:= ord(pwidechar(P)^);
  1010. inc(pwidechar(P));
  1011. end;
  1012. function Utf8ToOrd(var P:Pointer): Cardinal;
  1013. begin
  1014. // Should also check for illegal utf8 combinations
  1015. Result := Ord(PChar(P)^);
  1016. Inc(P);
  1017. if (Result and $80) <> 0 then
  1018. if (Ord(Result) and %11100000) = %11000000 then begin
  1019. Result := ((Result and %00011111) shl 6)
  1020. or (ord(PChar(P)^) and %00111111);
  1021. Inc(P);
  1022. end else if (Ord(Result) and %11110000) = %11100000 then begin
  1023. Result := ((Result and %00011111) shl 12)
  1024. or ((ord(PChar(P)^) and %00111111) shl 6)
  1025. or (ord((PChar(P)+1)^) and %00111111);
  1026. Inc(P,2);
  1027. end else begin
  1028. Result := ((ord(Result) and %00011111) shl 18)
  1029. or ((ord(PChar(P)^) and %00111111) shl 12)
  1030. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  1031. or (ord((PChar(P)+2)^) and %00111111);
  1032. Inc(P,3);
  1033. end;
  1034. end;
  1035. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  1036. procedure OutStr(s: String);
  1037. begin
  1038. if Length(s) > 0 then
  1039. Output.Write(s[1], Length(s));
  1040. end;
  1041. procedure OutLn(s: String);
  1042. begin
  1043. OutStr(s + LineEnding);
  1044. end;
  1045. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  1046. UseBytes: boolean = false);
  1047. var
  1048. res, NewStr: String;
  1049. w: Cardinal;
  1050. InString, NewInString: Boolean;
  1051. begin
  1052. if p = nil then begin
  1053. res:= '''''';
  1054. end
  1055. else
  1056. begin
  1057. res := '';
  1058. InString := False;
  1059. while P < LastP do
  1060. begin
  1061. NewInString := InString;
  1062. w := CharToOrdfunc(P);
  1063. if w = ord('''') then
  1064. begin //quote char
  1065. if not InString then
  1066. NewInString := True;
  1067. NewStr := '''''';
  1068. end
  1069. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  1070. begin //printable ascii or bytes
  1071. if not InString then
  1072. NewInString := True;
  1073. NewStr := char(w);
  1074. end
  1075. else
  1076. begin //ascii control chars, non ascii
  1077. if InString then
  1078. NewInString := False;
  1079. NewStr := '#' + IntToStr(w);
  1080. end;
  1081. if NewInString <> InString then
  1082. begin
  1083. NewStr := '''' + NewStr;
  1084. InString := NewInString;
  1085. end;
  1086. res := res + NewStr;
  1087. end;
  1088. if InString then
  1089. res := res + '''';
  1090. end;
  1091. OutStr(res);
  1092. end;
  1093. procedure OutString(s: String);
  1094. begin
  1095. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  1096. end;
  1097. procedure OutWString(W: WideString);
  1098. begin
  1099. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1100. end;
  1101. procedure OutUString(W: UnicodeString);
  1102. begin
  1103. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1104. end;
  1105. procedure OutUtf8Str(s: String);
  1106. begin
  1107. if Encoding=oteLFM then
  1108. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
  1109. else
  1110. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  1111. end;
  1112. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1113. begin
  1114. Result:=Input.ReadWord;
  1115. Result:=LEtoN(Result);
  1116. end;
  1117. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1118. begin
  1119. Result:=Input.ReadDWord;
  1120. Result:=LEtoN(Result);
  1121. end;
  1122. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1123. begin
  1124. Input.ReadBuffer(Result,sizeof(Result));
  1125. Result:=LEtoN(Result);
  1126. end;
  1127. {$ifndef FPUNONE}
  1128. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1129. function ExtendedToDouble(e : pointer) : double;
  1130. var mant : qword;
  1131. exp : smallint;
  1132. sign : boolean;
  1133. d : qword;
  1134. begin
  1135. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  1136. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  1137. mant:=LEtoN(mant);
  1138. exp:=LetoN(word(exp));
  1139. sign:=(exp and $8000)<>0;
  1140. if sign then exp:=exp and $7FFF;
  1141. case exp of
  1142. 0 : mant:=0; //if denormalized, value is too small for double,
  1143. //so it's always zero
  1144. $7FFF : exp:=2047 //either infinity or NaN
  1145. else
  1146. begin
  1147. dec(exp,16383-1023);
  1148. if (exp>=-51) and (exp<=0) then //can be denormalized
  1149. begin
  1150. mant:=mant shr (-exp);
  1151. exp:=0;
  1152. end
  1153. else
  1154. if (exp<-51) or (exp>2046) then //exponent too large.
  1155. begin
  1156. Result:=0;
  1157. exit;
  1158. end
  1159. else //normalized value
  1160. mant:=mant shl 1; //hide most significant bit
  1161. end;
  1162. end;
  1163. d:=word(exp);
  1164. d:=d shl 52;
  1165. mant:=mant shr 12;
  1166. d:=d or mant;
  1167. if sign then d:=d or $8000000000000000;
  1168. Result:=pdouble(@d)^;
  1169. end;
  1170. {$ENDIF}
  1171. {$endif}
  1172. function ReadInt(ValueType: TValueType): Int64;
  1173. begin
  1174. case ValueType of
  1175. vaInt8: Result := ShortInt(Input.ReadByte);
  1176. vaInt16: Result := SmallInt(ReadWord);
  1177. vaInt32: Result := LongInt(ReadDWord);
  1178. vaInt64: Result := Int64(ReadQWord);
  1179. end;
  1180. end;
  1181. function ReadInt: Int64;
  1182. begin
  1183. Result := ReadInt(TValueType(Input.ReadByte));
  1184. end;
  1185. {$ifndef FPUNONE}
  1186. function ReadExtended : extended;
  1187. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1188. var ext : array[0..9] of byte;
  1189. {$ENDIF}
  1190. begin
  1191. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1192. Input.ReadBuffer(ext[0],10);
  1193. Result:=ExtendedToDouble(@(ext[0]));
  1194. {$ELSE}
  1195. Input.ReadBuffer(Result,sizeof(Result));
  1196. {$ENDIF}
  1197. end;
  1198. {$endif}
  1199. function ReadSStr: String;
  1200. var
  1201. len: Byte;
  1202. begin
  1203. len := Input.ReadByte;
  1204. SetLength(Result, len);
  1205. if (len > 0) then
  1206. Input.ReadBuffer(Result[1], len);
  1207. end;
  1208. function ReadLStr: String;
  1209. var
  1210. len: DWord;
  1211. begin
  1212. len := ReadDWord;
  1213. SetLength(Result, len);
  1214. if (len > 0) then
  1215. Input.ReadBuffer(Result[1], len);
  1216. end;
  1217. function ReadWStr: WideString;
  1218. var
  1219. len: DWord;
  1220. {$IFDEF ENDIAN_BIG}
  1221. i : integer;
  1222. {$ENDIF}
  1223. begin
  1224. len := ReadDWord;
  1225. SetLength(Result, len);
  1226. if (len > 0) then
  1227. begin
  1228. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1229. {$IFDEF ENDIAN_BIG}
  1230. for i:=1 to len do
  1231. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1232. {$ENDIF}
  1233. end;
  1234. end;
  1235. function ReadUStr: UnicodeString;
  1236. var
  1237. len: DWord;
  1238. {$IFDEF ENDIAN_BIG}
  1239. i : integer;
  1240. {$ENDIF}
  1241. begin
  1242. len := ReadDWord;
  1243. SetLength(Result, len);
  1244. if (len > 0) then
  1245. begin
  1246. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1247. {$IFDEF ENDIAN_BIG}
  1248. for i:=1 to len do
  1249. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1250. {$ENDIF}
  1251. end;
  1252. end;
  1253. procedure ReadPropList(indent: String);
  1254. procedure ProcessValue(ValueType: TValueType; Indent: String);
  1255. procedure ProcessBinary;
  1256. var
  1257. ToDo, DoNow, i: LongInt;
  1258. lbuf: array[0..31] of Byte;
  1259. s: String;
  1260. begin
  1261. ToDo := ReadDWord;
  1262. OutLn('{');
  1263. while ToDo > 0 do begin
  1264. DoNow := ToDo;
  1265. if DoNow > 32 then DoNow := 32;
  1266. Dec(ToDo, DoNow);
  1267. s := Indent + ' ';
  1268. Input.ReadBuffer(lbuf, DoNow);
  1269. for i := 0 to DoNow - 1 do
  1270. s := s + IntToHex(lbuf[i], 2);
  1271. OutLn(s);
  1272. end;
  1273. OutLn(indent + '}');
  1274. end;
  1275. var
  1276. s: String;
  1277. { len: LongInt; }
  1278. IsFirst: Boolean;
  1279. {$ifndef FPUNONE}
  1280. ext: Extended;
  1281. {$endif}
  1282. begin
  1283. case ValueType of
  1284. vaList: begin
  1285. OutStr('(');
  1286. IsFirst := True;
  1287. while True do begin
  1288. ValueType := TValueType(Input.ReadByte);
  1289. if ValueType = vaNull then break;
  1290. if IsFirst then begin
  1291. OutLn('');
  1292. IsFirst := False;
  1293. end;
  1294. OutStr(Indent + ' ');
  1295. ProcessValue(ValueType, Indent + ' ');
  1296. end;
  1297. OutLn(Indent + ')');
  1298. end;
  1299. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  1300. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  1301. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  1302. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  1303. {$ifndef FPUNONE}
  1304. vaExtended: begin
  1305. ext:=ReadExtended;
  1306. Str(ext,S);// Do not use localized strings.
  1307. OutLn(S);
  1308. end;
  1309. {$endif}
  1310. vaString: begin
  1311. OutString(ReadSStr);
  1312. OutLn('');
  1313. end;
  1314. vaIdent: OutLn(ReadSStr);
  1315. vaFalse: OutLn('False');
  1316. vaTrue: OutLn('True');
  1317. vaBinary: ProcessBinary;
  1318. vaSet: begin
  1319. OutStr('[');
  1320. IsFirst := True;
  1321. while True do begin
  1322. s := ReadSStr;
  1323. if Length(s) = 0 then break;
  1324. if not IsFirst then OutStr(', ');
  1325. IsFirst := False;
  1326. OutStr(s);
  1327. end;
  1328. OutLn(']');
  1329. end;
  1330. vaLString:
  1331. begin
  1332. OutString(ReadLStr);
  1333. OutLn('');
  1334. end;
  1335. vaWString:
  1336. begin
  1337. OutWString(ReadWStr);
  1338. OutLn('');
  1339. end;
  1340. vaUString:
  1341. begin
  1342. OutWString(ReadWStr);
  1343. OutLn('');
  1344. end;
  1345. vaNil:
  1346. OutLn('nil');
  1347. vaCollection: begin
  1348. OutStr('<');
  1349. while Input.ReadByte <> 0 do begin
  1350. OutLn(Indent);
  1351. Input.Seek(-1, soFromCurrent);
  1352. OutStr(indent + ' item');
  1353. ValueType := TValueType(Input.ReadByte);
  1354. if ValueType <> vaList then
  1355. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1356. OutLn('');
  1357. ReadPropList(indent + ' ');
  1358. OutStr(indent + ' end');
  1359. end;
  1360. OutLn('>');
  1361. end;
  1362. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1363. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1364. vaDate: begin OutLn('!!Date!!'); exit end;}
  1365. vaUTF8String: begin
  1366. OutUtf8Str(ReadLStr);
  1367. OutLn('');
  1368. end;
  1369. else
  1370. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1371. end;
  1372. end;
  1373. begin
  1374. while Input.ReadByte <> 0 do begin
  1375. Input.Seek(-1, soFromCurrent);
  1376. OutStr(indent + ReadSStr + ' = ');
  1377. ProcessValue(TValueType(Input.ReadByte), Indent);
  1378. end;
  1379. end;
  1380. procedure ReadObject(indent: String);
  1381. var
  1382. b: Byte;
  1383. ObjClassName, ObjName: String;
  1384. ChildPos: LongInt;
  1385. begin
  1386. // Check for FilerFlags
  1387. b := Input.ReadByte;
  1388. if (b and $f0) = $f0 then begin
  1389. if (b and 2) <> 0 then ChildPos := ReadInt;
  1390. end else begin
  1391. b := 0;
  1392. Input.Seek(-1, soFromCurrent);
  1393. end;
  1394. ObjClassName := ReadSStr;
  1395. ObjName := ReadSStr;
  1396. OutStr(Indent);
  1397. if (b and 1) <> 0 then OutStr('inherited')
  1398. else
  1399. if (b and 4) <> 0 then OutStr('inline')
  1400. else OutStr('object');
  1401. OutStr(' ');
  1402. if ObjName <> '' then
  1403. OutStr(ObjName + ': ');
  1404. OutStr(ObjClassName);
  1405. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1406. OutLn('');
  1407. ReadPropList(indent + ' ');
  1408. while Input.ReadByte <> 0 do begin
  1409. Input.Seek(-1, soFromCurrent);
  1410. ReadObject(indent + ' ');
  1411. end;
  1412. OutLn(indent + 'end');
  1413. end;
  1414. type
  1415. PLongWord = ^LongWord;
  1416. const
  1417. signature: PChar = 'TPF0';
  1418. begin
  1419. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1420. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1421. ReadObject('');
  1422. end;
  1423. procedure ObjectBinaryToText(Input, Output: TStream);
  1424. begin
  1425. ObjectBinaryToText(Input,Output,oteDFM);
  1426. end;
  1427. procedure ObjectTextToBinary(Input, Output: TStream);
  1428. var
  1429. parser: TParser;
  1430. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1431. begin
  1432. w:=NtoLE(w);
  1433. Output.WriteWord(w);
  1434. end;
  1435. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1436. begin
  1437. lw:=NtoLE(lw);
  1438. Output.WriteDWord(lw);
  1439. end;
  1440. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1441. begin
  1442. qw:=NtoLE(qw);
  1443. Output.WriteBuffer(qw,sizeof(qword));
  1444. end;
  1445. {$ifndef FPUNONE}
  1446. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1447. procedure DoubleToExtended(d : double; e : pointer);
  1448. var mant : qword;
  1449. exp : smallint;
  1450. sign : boolean;
  1451. begin
  1452. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1453. exp :=(qword(d) shr 52) and $7FF;
  1454. sign:=(qword(d) and $8000000000000000)<>0;
  1455. case exp of
  1456. 0 : begin
  1457. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1458. begin
  1459. exp:=16383-1022;
  1460. while (mant and $8000000000000000)=0 do
  1461. begin
  1462. dec(exp);
  1463. mant:=mant shl 1;
  1464. end;
  1465. dec(exp); //don't shift, most significant bit is not hidden in extended
  1466. end;
  1467. end;
  1468. 2047 : exp:=$7FFF //either infinity or NaN
  1469. else
  1470. begin
  1471. inc(exp,16383-1023);
  1472. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1473. end;
  1474. end;
  1475. if sign then exp:=exp or $8000;
  1476. mant:=NtoLE(mant);
  1477. exp:=NtoLE(word(exp));
  1478. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1479. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1480. end;
  1481. {$ENDIF}
  1482. procedure WriteExtended(e : extended);
  1483. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1484. var ext : array[0..9] of byte;
  1485. {$ENDIF}
  1486. begin
  1487. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1488. DoubleToExtended(e,@(ext[0]));
  1489. Output.WriteBuffer(ext[0],10);
  1490. {$ELSE}
  1491. Output.WriteBuffer(e,sizeof(e));
  1492. {$ENDIF}
  1493. end;
  1494. {$endif}
  1495. procedure WriteString(s: String);
  1496. var size : byte;
  1497. begin
  1498. if length(s)>255 then size:=255
  1499. else size:=length(s);
  1500. Output.WriteByte(size);
  1501. if Length(s) > 0 then
  1502. Output.WriteBuffer(s[1], size);
  1503. end;
  1504. procedure WriteLString(Const s: String);
  1505. begin
  1506. WriteDWord(Length(s));
  1507. if Length(s) > 0 then
  1508. Output.WriteBuffer(s[1], Length(s));
  1509. end;
  1510. procedure WriteWString(Const s: WideString);
  1511. var len : longword;
  1512. {$IFDEF ENDIAN_BIG}
  1513. i : integer;
  1514. ws : widestring;
  1515. {$ENDIF}
  1516. begin
  1517. len:=Length(s);
  1518. WriteDWord(len);
  1519. if len > 0 then
  1520. begin
  1521. {$IFDEF ENDIAN_BIG}
  1522. setlength(ws,len);
  1523. for i:=1 to len do
  1524. ws[i]:=widechar(SwapEndian(word(s[i])));
  1525. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1526. {$ELSE}
  1527. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1528. {$ENDIF}
  1529. end;
  1530. end;
  1531. procedure WriteInteger(value: Int64);
  1532. begin
  1533. if (value >= -128) and (value <= 127) then begin
  1534. Output.WriteByte(Ord(vaInt8));
  1535. Output.WriteByte(byte(value));
  1536. end else if (value >= -32768) and (value <= 32767) then begin
  1537. Output.WriteByte(Ord(vaInt16));
  1538. WriteWord(word(value));
  1539. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1540. Output.WriteByte(Ord(vaInt32));
  1541. WriteDWord(longword(value));
  1542. end else begin
  1543. Output.WriteByte(ord(vaInt64));
  1544. WriteQWord(qword(value));
  1545. end;
  1546. end;
  1547. procedure ProcessWideString(const left : widestring);
  1548. var ws : widestring;
  1549. begin
  1550. ws:=left+parser.TokenWideString;
  1551. while parser.NextToken = '+' do
  1552. begin
  1553. parser.NextToken; // Get next string fragment
  1554. if not (parser.Token in [toString,toWString]) then
  1555. parser.CheckToken(toWString);
  1556. ws:=ws+parser.TokenWideString;
  1557. end;
  1558. Output.WriteByte(Ord(vaWstring));
  1559. WriteWString(ws);
  1560. end;
  1561. procedure ProcessProperty; forward;
  1562. procedure ProcessValue;
  1563. var
  1564. {$ifndef FPUNONE}
  1565. flt: Extended;
  1566. {$endif}
  1567. s: String;
  1568. stream: TMemoryStream;
  1569. begin
  1570. case parser.Token of
  1571. toInteger:
  1572. begin
  1573. WriteInteger(parser.TokenInt);
  1574. parser.NextToken;
  1575. end;
  1576. {$ifndef FPUNONE}
  1577. toFloat:
  1578. begin
  1579. Output.WriteByte(Ord(vaExtended));
  1580. flt := Parser.TokenFloat;
  1581. WriteExtended(flt);
  1582. parser.NextToken;
  1583. end;
  1584. {$endif}
  1585. toString:
  1586. begin
  1587. s := parser.TokenString;
  1588. while parser.NextToken = '+' do
  1589. begin
  1590. parser.NextToken; // Get next string fragment
  1591. case parser.Token of
  1592. toString : s:=s+parser.TokenString;
  1593. toWString : begin
  1594. ProcessWideString(s);
  1595. exit;
  1596. end
  1597. else parser.CheckToken(toString);
  1598. end;
  1599. end;
  1600. if (length(S)>255) then
  1601. begin
  1602. Output.WriteByte(Ord(vaLString));
  1603. WriteLString(S);
  1604. end
  1605. else
  1606. begin
  1607. Output.WriteByte(Ord(vaString));
  1608. WriteString(s);
  1609. end;
  1610. end;
  1611. toWString:
  1612. ProcessWideString('');
  1613. toSymbol:
  1614. begin
  1615. if CompareText(parser.TokenString, 'True') = 0 then
  1616. Output.WriteByte(Ord(vaTrue))
  1617. else if CompareText(parser.TokenString, 'False') = 0 then
  1618. Output.WriteByte(Ord(vaFalse))
  1619. else if CompareText(parser.TokenString, 'nil') = 0 then
  1620. Output.WriteByte(Ord(vaNil))
  1621. else
  1622. begin
  1623. Output.WriteByte(Ord(vaIdent));
  1624. WriteString(parser.TokenComponentIdent);
  1625. end;
  1626. Parser.NextToken;
  1627. end;
  1628. // Set
  1629. '[':
  1630. begin
  1631. parser.NextToken;
  1632. Output.WriteByte(Ord(vaSet));
  1633. if parser.Token <> ']' then
  1634. while True do
  1635. begin
  1636. parser.CheckToken(toSymbol);
  1637. WriteString(parser.TokenString);
  1638. parser.NextToken;
  1639. if parser.Token = ']' then
  1640. break;
  1641. parser.CheckToken(',');
  1642. parser.NextToken;
  1643. end;
  1644. Output.WriteByte(0);
  1645. parser.NextToken;
  1646. end;
  1647. // List
  1648. '(':
  1649. begin
  1650. parser.NextToken;
  1651. Output.WriteByte(Ord(vaList));
  1652. while parser.Token <> ')' do
  1653. ProcessValue;
  1654. Output.WriteByte(0);
  1655. parser.NextToken;
  1656. end;
  1657. // Collection
  1658. '<':
  1659. begin
  1660. parser.NextToken;
  1661. Output.WriteByte(Ord(vaCollection));
  1662. while parser.Token <> '>' do
  1663. begin
  1664. parser.CheckTokenSymbol('item');
  1665. parser.NextToken;
  1666. // ConvertOrder
  1667. Output.WriteByte(Ord(vaList));
  1668. while not parser.TokenSymbolIs('end') do
  1669. ProcessProperty;
  1670. parser.NextToken; // Skip 'end'
  1671. Output.WriteByte(0);
  1672. end;
  1673. Output.WriteByte(0);
  1674. parser.NextToken;
  1675. end;
  1676. // Binary data
  1677. '{':
  1678. begin
  1679. Output.WriteByte(Ord(vaBinary));
  1680. stream := TMemoryStream.Create;
  1681. try
  1682. parser.HexToBinary(stream);
  1683. WriteDWord(stream.Size);
  1684. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1685. finally
  1686. stream.Free;
  1687. end;
  1688. parser.NextToken;
  1689. end;
  1690. else
  1691. parser.Error(SInvalidProperty);
  1692. end;
  1693. end;
  1694. procedure ProcessProperty;
  1695. var
  1696. name: String;
  1697. begin
  1698. // Get name of property
  1699. parser.CheckToken(toSymbol);
  1700. name := parser.TokenString;
  1701. while True do begin
  1702. parser.NextToken;
  1703. if parser.Token <> '.' then break;
  1704. parser.NextToken;
  1705. parser.CheckToken(toSymbol);
  1706. name := name + '.' + parser.TokenString;
  1707. end;
  1708. WriteString(name);
  1709. parser.CheckToken('=');
  1710. parser.NextToken;
  1711. ProcessValue;
  1712. end;
  1713. procedure ProcessObject;
  1714. var
  1715. Flags: Byte;
  1716. ObjectName, ObjectType: String;
  1717. ChildPos: Integer;
  1718. begin
  1719. if parser.TokenSymbolIs('OBJECT') then
  1720. Flags :=0 { IsInherited := False }
  1721. else begin
  1722. if parser.TokenSymbolIs('INHERITED') then
  1723. Flags := 1 { IsInherited := True; }
  1724. else begin
  1725. parser.CheckTokenSymbol('INLINE');
  1726. Flags := 4;
  1727. end;
  1728. end;
  1729. parser.NextToken;
  1730. parser.CheckToken(toSymbol);
  1731. ObjectName := '';
  1732. ObjectType := parser.TokenString;
  1733. parser.NextToken;
  1734. if parser.Token = ':' then begin
  1735. parser.NextToken;
  1736. parser.CheckToken(toSymbol);
  1737. ObjectName := ObjectType;
  1738. ObjectType := parser.TokenString;
  1739. parser.NextToken;
  1740. if parser.Token = '[' then begin
  1741. parser.NextToken;
  1742. ChildPos := parser.TokenInt;
  1743. parser.NextToken;
  1744. parser.CheckToken(']');
  1745. parser.NextToken;
  1746. Flags := Flags or 2;
  1747. end;
  1748. end;
  1749. if Flags <> 0 then begin
  1750. Output.WriteByte($f0 or Flags);
  1751. if (Flags and 2) <> 0 then
  1752. WriteInteger(ChildPos);
  1753. end;
  1754. WriteString(ObjectType);
  1755. WriteString(ObjectName);
  1756. // Convert property list
  1757. while not (parser.TokenSymbolIs('END') or
  1758. parser.TokenSymbolIs('OBJECT') or
  1759. parser.TokenSymbolIs('INHERITED') or
  1760. parser.TokenSymbolIs('INLINE')) do
  1761. ProcessProperty;
  1762. Output.WriteByte(0); // Terminate property list
  1763. // Convert child objects
  1764. while not parser.TokenSymbolIs('END') do ProcessObject;
  1765. parser.NextToken; // Skip end token
  1766. Output.WriteByte(0); // Terminate property list
  1767. end;
  1768. const
  1769. signature: PChar = 'TPF0';
  1770. begin
  1771. parser := TParser.Create(Input);
  1772. try
  1773. Output.WriteBuffer(signature[0], 4);
  1774. ProcessObject;
  1775. finally
  1776. parser.Free;
  1777. end;
  1778. end;
  1779. procedure ObjectResourceToText(Input, Output: TStream);
  1780. begin
  1781. Input.ReadResHeader;
  1782. ObjectBinaryToText(Input, Output);
  1783. end;
  1784. procedure ObjectTextToResource(Input, Output: TStream);
  1785. var
  1786. StartPos, FixupInfo: LongInt;
  1787. parser: TParser;
  1788. name: String;
  1789. begin
  1790. // Get form type name
  1791. StartPos := Input.Position;
  1792. parser := TParser.Create(Input);
  1793. try
  1794. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1795. parser.NextToken;
  1796. parser.CheckToken(toSymbol);
  1797. parser.NextToken;
  1798. parser.CheckToken(':');
  1799. parser.NextToken;
  1800. parser.CheckToken(toSymbol);
  1801. name := parser.TokenString;
  1802. finally
  1803. parser.Free;
  1804. Input.Position := StartPos;
  1805. end;
  1806. name := UpperCase(name);
  1807. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1808. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1809. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1810. end;
  1811. { Utility routines }
  1812. function LineStart(Buffer, BufPos: PChar): PChar;
  1813. begin
  1814. Result := BufPos;
  1815. while Result > Buffer do begin
  1816. Dec(Result);
  1817. if Result[0] = #10 then break;
  1818. end;
  1819. end;
  1820. procedure CommonInit;
  1821. begin
  1822. SynchronizeTimeoutEvent:=RtlEventCreate;
  1823. InitCriticalSection(ThreadQueueLock);
  1824. MainThreadID:=GetCurrentThreadID;
  1825. ExternalThreads := TThreadList.Create;
  1826. TThread.FProcessorCount := CPUCount;
  1827. InitCriticalsection(ResolveSection);
  1828. InitHandlerList:=Nil;
  1829. FindGlobalComponentList:=nil;
  1830. IntConstList := TThreadList.Create;
  1831. ClassList := TThreadList.Create;
  1832. ClassAliasList := TStringList.Create;
  1833. { on unix this maps to a simple rw synchornizer }
  1834. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1835. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1836. end;
  1837. procedure CommonCleanup;
  1838. var
  1839. i: Integer;
  1840. tmpentry: TThread.PThreadQueueEntry;
  1841. begin
  1842. GlobalNameSpace.BeginWrite;
  1843. with IntConstList.LockList do
  1844. try
  1845. for i := 0 to Count - 1 do
  1846. TIntConst(Items[I]).Free;
  1847. finally
  1848. IntConstList.UnlockList;
  1849. end;
  1850. IntConstList.Free;
  1851. ClassList.Free;
  1852. ClassAliasList.Free;
  1853. RemoveFixupReferences(nil, '');
  1854. DoneCriticalsection(ResolveSection);
  1855. GlobalLists.Free;
  1856. ComponentPages.Free;
  1857. FreeAndNil(NeedResolving);
  1858. { GlobalNameSpace is an interface so this is enough }
  1859. GlobalNameSpace:=nil;
  1860. if (InitHandlerList<>Nil) then
  1861. for i := 0 to InitHandlerList.Count - 1 do
  1862. TInitHandler(InitHandlerList.Items[I]).Free;
  1863. InitHandlerList.Free;
  1864. InitHandlerList:=Nil;
  1865. FindGlobalComponentList.Free;
  1866. FindGlobalComponentList:=nil;
  1867. with ExternalThreads.LockList do
  1868. try
  1869. for i := 0 to Count - 1 do
  1870. TThread(Items[i]).Free;
  1871. finally
  1872. ExternalThreads.UnlockList;
  1873. end;
  1874. FreeAndNil(ExternalThreads);
  1875. RtlEventDestroy(SynchronizeTimeoutEvent);
  1876. { clean up the queue, but keep in mind that the entries used for Synchronize
  1877. are owned by the corresponding TThread }
  1878. while Assigned(ThreadQueueHead) do begin
  1879. tmpentry := ThreadQueueHead;
  1880. ThreadQueueHead := tmpentry^.Next;
  1881. if not Assigned(tmpentry^.SyncEvent) then
  1882. Dispose(tmpentry);
  1883. end;
  1884. DoneCriticalSection(ThreadQueueLock);
  1885. end;
  1886. { TFiler implementation }
  1887. {$i filer.inc}
  1888. { TReader implementation }
  1889. {$i reader.inc}
  1890. { TWriter implementations }
  1891. {$i writer.inc}
  1892. {$i twriter.inc}