classes.inc 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769
  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. {$ifdef FPC_HAS_REFERENCE_PROCEDURE}
  584. class procedure TThread.ForceQueue(aThread: TThread; aMethod: TThreadProcedure); static;
  585. begin
  586. InternalQueue(aThread, aMethod, True);
  587. end;
  588. {$endif}
  589. class procedure TThread.RemoveQueuedEvents(aThread: TThread; aMethod: TThreadMethod);
  590. var
  591. entry, tmpentry, lastentry: PThreadQueueEntry;
  592. begin
  593. { anything to do at all? }
  594. if not Assigned(aThread) and not Assigned(aMethod) then
  595. Exit;
  596. {$ifdef FPC_HAS_FEATURE_THREADING}
  597. System.EnterCriticalSection(ThreadQueueLock);
  598. try
  599. {$endif}
  600. lastentry := Nil;
  601. entry := ThreadQueueHead;
  602. while Assigned(entry) do begin
  603. if
  604. { only entries not added by Synchronize }
  605. not Assigned(entry^.SyncEvent)
  606. { check for the thread }
  607. and (not Assigned(aThread) or (entry^.Thread = aThread) or (entry^.ThreadID = aThread.ThreadID))
  608. { check for the method }
  609. and (not Assigned(aMethod) or
  610. (
  611. (TMethod(entry^.Method).Code = TMethod(aMethod).Code) and
  612. (TMethod(entry^.Method).Data = TMethod(aMethod).Data)
  613. ))
  614. then begin
  615. { ok, we need to remove this entry }
  616. tmpentry := entry;
  617. if Assigned(lastentry) then
  618. lastentry^.Next := entry^.Next;
  619. entry := entry^.Next;
  620. if ThreadQueueHead = tmpentry then
  621. ThreadQueueHead := entry;
  622. if ThreadQueueTail = tmpentry then
  623. ThreadQueueTail := lastentry;
  624. { only dispose events added by Queue }
  625. if not Assigned(tmpentry^.SyncEvent) then
  626. Dispose(tmpentry);
  627. end else begin
  628. { leave this entry }
  629. lastentry := entry;
  630. entry := entry^.Next;
  631. end;
  632. end;
  633. {$ifdef FPC_HAS_FEATURE_THREADING}
  634. finally
  635. System.LeaveCriticalSection(ThreadQueueLock);
  636. end;
  637. {$endif}
  638. end;
  639. class procedure TThread.RemoveQueuedEvents(aMethod: TThreadMethod);
  640. begin
  641. RemoveQueuedEvents(Nil, aMethod);
  642. end;
  643. class procedure TThread.RemoveQueuedEvents(aThread: TThread);
  644. begin
  645. RemoveQueuedEvents(aThread, Nil);
  646. end;
  647. class function TThread.CheckTerminated: Boolean;
  648. begin
  649. { this method only works with threads created by TThread, so we can make a
  650. shortcut here }
  651. if not Assigned(CurrentThreadVar) then
  652. raise EThreadExternalException.Create(SThreadExternal);
  653. Result := CurrentThreadVar.FTerminated;
  654. end;
  655. class procedure TThread.SetReturnValue(aValue: Integer);
  656. begin
  657. { this method only works with threads created by TThread, so we can make a
  658. shortcut here }
  659. if not Assigned(CurrentThreadVar) then
  660. raise EThreadExternalException.Create(SThreadExternal);
  661. CurrentThreadVar.FReturnValue := aValue;
  662. end;
  663. class function TThread.CreateAnonymousThread(aProc: TProcedure): TThread;
  664. begin
  665. if not Assigned(aProc) then
  666. raise Exception.Create(SNoProcGiven);
  667. Result := TAnonymousThread.Create(aProc);
  668. end;
  669. class procedure TThread.NameThreadForDebugging(aThreadName: UnicodeString; aThreadID: TThreadID);
  670. begin
  671. {$ifdef FPC_HAS_FEATURE_THREADING}
  672. SetThreadDebugName(aThreadID, aThreadName);
  673. {$endif}
  674. end;
  675. class procedure TThread.NameThreadForDebugging(aThreadName: AnsiString; aThreadID: TThreadID);
  676. begin
  677. {$ifdef FPC_HAS_FEATURE_THREADING}
  678. SetThreadDebugName(aThreadID, aThreadName);
  679. {$endif}
  680. end;
  681. class procedure TThread.Yield;
  682. begin
  683. {$ifdef FPC_HAS_FEATURE_THREADING}
  684. ThreadSwitch;
  685. {$endif}
  686. end;
  687. class procedure TThread.Sleep(aMilliseconds: Cardinal);
  688. begin
  689. SysUtils.Sleep(aMilliseconds);
  690. end;
  691. class procedure TThread.SpinWait(aIterations: LongWord);
  692. var
  693. i: LongWord;
  694. begin
  695. { yes, it's just a simple busy wait to burn some cpu cycles... and as the job
  696. of this loop is to burn CPU cycles we switch off any optimizations that
  697. could interfere with this (e.g. loop unrolling) }
  698. { Do *NOT* do $PUSH, $OPTIMIZATIONS OFF, <code>, $POP because optimization is
  699. not a local switch, which means $PUSH/POP doesn't affect it, so that turns
  700. off *ALL* optimizations for code below this point. Thanks to this we shipped
  701. large parts of the classes unit with optimizations off between 2012-12-27
  702. and 2014-06-06.
  703. Instead, use a global var for the spinlock, because that is always handled
  704. as volatile, so the access won't be optimized away by the compiler. (KB) }
  705. for i:=1 to aIterations do
  706. begin
  707. Inc(SpinWaitDummy); // SpinWaitDummy *MUST* be global
  708. end;
  709. end;
  710. {$ifndef HAS_TTHREAD_GETSYSTEMTIMES}
  711. class procedure TThread.GetSystemTimes(out aSystemTimes: TSystemTimes);
  712. begin
  713. { by default we just return a zeroed out record }
  714. FillChar(aSystemTimes, SizeOf(aSystemTimes), 0);
  715. end;
  716. {$endif}
  717. class function TThread.GetTickCount: LongWord;
  718. begin
  719. Result := SysUtils.GetTickCount;
  720. end;
  721. class function TThread.GetTickCount64: QWord;
  722. begin
  723. Result := SysUtils.GetTickCount64;
  724. end;
  725. { TSimpleThread allows objects to create a threading method without defining
  726. a new thread class }
  727. Type
  728. TSimpleThread = class(TThread)
  729. private
  730. FExecuteMethod: TThreadExecuteHandler;
  731. protected
  732. procedure Execute; override;
  733. public
  734. constructor Create(ExecuteMethod: TThreadExecuteHandler; AOnterminate : TNotifyEvent);
  735. end;
  736. TSimpleStatusThread = class(TThread)
  737. private
  738. FExecuteMethod: TThreadExecuteStatusHandler;
  739. FStatus : String;
  740. FOnStatus : TThreadStatusNotifyEvent;
  741. protected
  742. procedure Execute; override;
  743. Procedure DoStatus;
  744. Procedure SetStatus(Const AStatus : String);
  745. public
  746. constructor Create(ExecuteMethod: TThreadExecuteStatusHandler; AOnStatus : TThreadStatusNotifyEvent; AOnterminate : TNotifyEvent);
  747. end;
  748. TSimpleProcThread = class(TThread)
  749. private
  750. FExecuteMethod: TThreadExecuteCallBack;
  751. FCallOnTerminate : TNotifyCallBack;
  752. FData : Pointer;
  753. protected
  754. Procedure TerminateCallBack(Sender : TObject);
  755. procedure Execute; override;
  756. public
  757. constructor Create(ExecuteMethod: TThreadExecuteCallBack; AData : Pointer; AOnterminate : TNotifyCallBack);
  758. end;
  759. TSimpleStatusProcThread = class(TThread)
  760. private
  761. FExecuteMethod: TThreadExecuteStatusCallBack;
  762. FCallOnTerminate : TNotifyCallBack;
  763. FStatus : String;
  764. FOnStatus : TThreadStatusNotifyCallBack;
  765. FData : Pointer;
  766. protected
  767. procedure Execute; override;
  768. Procedure DoStatus;
  769. Procedure SetStatus(Const AStatus : String);
  770. Procedure TerminateCallBack(Sender : TObject);
  771. public
  772. constructor Create(ExecuteMethod: TThreadExecuteStatusCallBack; AData : Pointer; AOnStatus : TThreadStatusNotifyCallBack; AOnterminate : TNotifyCallBack);
  773. end;
  774. { TSimpleThread }
  775. constructor TSimpleThread.Create(ExecuteMethod: TThreadExecuteHandler; AOnTerminate: TNotifyEvent);
  776. begin
  777. FExecuteMethod := ExecuteMethod;
  778. OnTerminate := AOnTerminate;
  779. inherited Create(False);
  780. end;
  781. procedure TSimpleThread.Execute;
  782. begin
  783. FreeOnTerminate := True;
  784. FExecuteMethod;
  785. end;
  786. { TSimpleStatusThread }
  787. constructor TSimpleStatusThread.Create(ExecuteMethod: TThreadExecuteStatusHandler;AOnStatus : TThreadStatusNotifyEvent; AOnTerminate: TNotifyEvent);
  788. begin
  789. FExecuteMethod := ExecuteMethod;
  790. OnTerminate := AOnTerminate;
  791. FOnStatus:=AOnStatus;
  792. FStatus:='';
  793. inherited Create(False);
  794. end;
  795. procedure TSimpleStatusThread.Execute;
  796. begin
  797. FreeOnTerminate := True;
  798. FExecuteMethod(@SetStatus);
  799. end;
  800. procedure TSimpleStatusThread.SetStatus(Const AStatus : String);
  801. begin
  802. If (AStatus=FStatus) then
  803. exit;
  804. FStatus:=AStatus;
  805. If Assigned(FOnStatus) then
  806. Synchronize(@DoStatus);
  807. end;
  808. procedure TSimpleStatusThread.DoStatus;
  809. begin
  810. FOnStatus(Self,FStatus);
  811. end;
  812. { TSimpleProcThread }
  813. constructor TSimpleProcThread.Create(ExecuteMethod: TThreadExecuteCallBack; AData : Pointer; AOnTerminate: TNotifyCallBack);
  814. begin
  815. FExecuteMethod := ExecuteMethod;
  816. FCallOnTerminate := AOnTerminate;
  817. FData:=AData;
  818. If Assigned(FCallOnTerminate) then
  819. OnTerminate:=@TerminateCallBack;
  820. inherited Create(False);
  821. end;
  822. procedure TSimpleProcThread.Execute;
  823. begin
  824. FreeOnTerminate := True;
  825. FExecuteMethod(FData);
  826. end;
  827. procedure TSimpleProcThread.TerminateCallBack(Sender : TObject);
  828. begin
  829. if Assigned(FCallOnTerminate) then
  830. FCallOnTerminate(Sender,FData);
  831. end;
  832. { TSimpleStatusProcThread }
  833. constructor TSimpleStatusProcThread.Create(ExecuteMethod: TThreadExecuteStatusCallback; AData : Pointer; AOnStatus : TThreadStatusNotifyCallBack; AOnTerminate: TNotifyCallBack);
  834. begin
  835. FExecuteMethod := ExecuteMethod;
  836. FCallOnTerminate := AOnTerminate;
  837. FData:=AData;
  838. If Assigned(FCallOnTerminate) then
  839. OnTerminate:=@TerminateCallBack;
  840. FOnStatus:=AOnStatus;
  841. FStatus:='';
  842. inherited Create(False);
  843. end;
  844. procedure TSimpleStatusProcThread.Execute;
  845. begin
  846. FreeOnTerminate := True;
  847. FExecuteMethod(FData,@SetStatus);
  848. end;
  849. procedure TSimpleStatusProcThread.SetStatus(Const AStatus : String);
  850. begin
  851. If (AStatus=FStatus) then
  852. exit;
  853. FStatus:=AStatus;
  854. If Assigned(FOnStatus) then
  855. Synchronize(@DoStatus);
  856. end;
  857. procedure TSimpleStatusProcThread.DoStatus;
  858. begin
  859. FOnStatus(Self,FData,FStatus);
  860. end;
  861. procedure TSimpleStatusProcThread.TerminateCallBack(Sender : TObject);
  862. begin
  863. if Assigned(FCallOnTerminate) then
  864. FCallOnTerminate(Sender,FData);
  865. end;
  866. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteHandler; AOnTerminate : TNotifyEvent = Nil) : TThread;
  867. begin
  868. Result:=TSimpleThread.Create(AMethod,AOnTerminate);
  869. end;
  870. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteCallback; AData : Pointer; AOnTerminate : TNotifyCallback = Nil) : TThread;
  871. begin
  872. Result:=TSimpleProcThread.Create(AMethod,AData,AOnTerminate);
  873. end;
  874. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteStatusHandler; AOnStatus : TThreadStatusNotifyEvent; AOnTerminate : TNotifyEvent = Nil) : TThread;
  875. begin
  876. If Not Assigned(AOnStatus) then
  877. Raise EThread.Create(SErrStatusCallBackRequired);
  878. Result:=TSimpleStatusThread.Create(AMethod,AOnStatus,AOnTerminate);
  879. end;
  880. Class Function TThread.ExecuteInThread(AMethod : TThreadExecuteStatusCallback; AOnStatus : TThreadStatusNotifyCallback;AData : Pointer = Nil; AOnTerminate : TNotifyCallBack = Nil) : TThread;
  881. begin
  882. If Not Assigned(AOnStatus) then
  883. Raise EThread.Create(SErrStatusCallBackRequired);
  884. Result:=TSimpleStatusProcThread.Create(AMethod,AData,AOnStatus,AOnTerminate);
  885. end;
  886. { TPersistent implementation }
  887. {$i persist.inc }
  888. {$i sllist.inc}
  889. {$i resref.inc}
  890. { TComponent implementation }
  891. {$i compon.inc}
  892. { TBasicAction implementation }
  893. {$i action.inc}
  894. { TDataModule implementation }
  895. {$i dm.inc}
  896. { Class and component registration routines }
  897. {$I cregist.inc}
  898. { Interface related stuff }
  899. {$I intf.inc}
  900. {**********************************************************************
  901. * Miscellaneous procedures and functions *
  902. **********************************************************************}
  903. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings; AddEmptyStrings : Boolean = False): Integer;
  904. var
  905. b, c : pchar;
  906. procedure SkipWhitespace;
  907. begin
  908. while (c^ in Whitespace) do
  909. inc (c);
  910. end;
  911. procedure AddString;
  912. var
  913. l : integer;
  914. s : string;
  915. begin
  916. l := c-b;
  917. if (l > 0) or AddEmptyStrings then
  918. begin
  919. if assigned(Strings) then
  920. begin
  921. setlength(s, l);
  922. if l>0 then
  923. move (b^, s[1],l*SizeOf(char));
  924. Strings.Add (s);
  925. end;
  926. inc (result);
  927. end;
  928. end;
  929. var
  930. quoted : char;
  931. begin
  932. result := 0;
  933. c := Content;
  934. Quoted := #0;
  935. Separators := Separators + [#13, #10] - ['''','"'];
  936. SkipWhitespace;
  937. b := c;
  938. while (c^ <> #0) do
  939. begin
  940. if (c^ = Quoted) then
  941. begin
  942. if ((c+1)^ = Quoted) then
  943. inc (c)
  944. else
  945. Quoted := #0
  946. end
  947. else if (Quoted = #0) and (c^ in ['''','"']) then
  948. Quoted := c^;
  949. if (Quoted = #0) and (c^ in Separators) then
  950. begin
  951. AddString;
  952. inc (c);
  953. SkipWhitespace;
  954. b := c;
  955. end
  956. else
  957. inc (c);
  958. end;
  959. if (c <> b) then
  960. AddString;
  961. end;
  962. { Point and rectangle constructors }
  963. function Point(AX, AY: Integer): TPoint;
  964. begin
  965. with Result do
  966. begin
  967. X := AX;
  968. Y := AY;
  969. end;
  970. end;
  971. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  972. begin
  973. with Result do
  974. begin
  975. X := AX;
  976. Y := AY;
  977. end;
  978. end;
  979. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  980. begin
  981. with Result do
  982. begin
  983. Left := ALeft;
  984. Top := ATop;
  985. Right := ARight;
  986. Bottom := ABottom;
  987. end;
  988. end;
  989. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  990. begin
  991. with Result do
  992. begin
  993. Left := ALeft;
  994. Top := ATop;
  995. Right := ALeft + AWidth;
  996. Bottom := ATop + AHeight;
  997. end;
  998. end;
  999. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1000. begin
  1001. { lazy, but should work }
  1002. result:=QWord(P1)=QWord(P2);
  1003. end;
  1004. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1005. begin
  1006. { lazy, but should work }
  1007. result:=DWord(P1)=DWord(P2);
  1008. end;
  1009. function InvalidPoint(X, Y: Integer): Boolean;
  1010. begin
  1011. result:=(X=-1) and (Y=-1);
  1012. end;
  1013. function InvalidPoint(const At: TPoint): Boolean;
  1014. begin
  1015. result:=(At.x=-1) and (At.y=-1);
  1016. end;
  1017. function InvalidPoint(const At: TSmallPoint): Boolean;
  1018. begin
  1019. result:=(At.x=-1) and (At.y=-1);
  1020. end;
  1021. { Object filing routines }
  1022. var
  1023. IntConstList: TThreadList;
  1024. type
  1025. TIntConst = class
  1026. IntegerType: PTypeInfo; // The integer type RTTI pointer
  1027. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  1028. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  1029. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  1030. AIntToIdent: TIntToIdent);
  1031. end;
  1032. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  1033. AIntToIdent: TIntToIdent);
  1034. begin
  1035. IntegerType := AIntegerType;
  1036. IdentToIntFn := AIdentToInt;
  1037. IntToIdentFn := AIntToIdent;
  1038. end;
  1039. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  1040. IntToIdentFn: TIntToIdent);
  1041. begin
  1042. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  1043. end;
  1044. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  1045. var
  1046. i: Integer;
  1047. begin
  1048. with IntConstList.LockList do
  1049. try
  1050. for i := 0 to Count - 1 do
  1051. if TIntConst(Items[i]).IntegerType = AIntegerType then
  1052. exit(TIntConst(Items[i]).IntToIdentFn);
  1053. Result := nil;
  1054. finally
  1055. IntConstList.UnlockList;
  1056. end;
  1057. end;
  1058. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  1059. var
  1060. i: Integer;
  1061. begin
  1062. with IntConstList.LockList do
  1063. try
  1064. for i := 0 to Count - 1 do
  1065. with TIntConst(Items[I]) do
  1066. if TIntConst(Items[I]).IntegerType = AIntegerType then
  1067. exit(IdentToIntFn);
  1068. Result := nil;
  1069. finally
  1070. IntConstList.UnlockList;
  1071. end;
  1072. end;
  1073. function IdentToInt(const Ident: String; out Int: LongInt;
  1074. const Map: array of TIdentMapEntry): Boolean;
  1075. var
  1076. i: Integer;
  1077. begin
  1078. for i := Low(Map) to High(Map) do
  1079. if CompareText(Map[i].Name, Ident) = 0 then
  1080. begin
  1081. Int := Map[i].Value;
  1082. exit(True);
  1083. end;
  1084. Result := False;
  1085. end;
  1086. function IntToIdent(Int: LongInt; var Ident: String;
  1087. const Map: array of TIdentMapEntry): Boolean;
  1088. var
  1089. i: Integer;
  1090. begin
  1091. for i := Low(Map) to High(Map) do
  1092. if Map[i].Value = Int then
  1093. begin
  1094. Ident := Map[i].Name;
  1095. exit(True);
  1096. end;
  1097. Result := False;
  1098. end;
  1099. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  1100. var
  1101. i : Integer;
  1102. begin
  1103. with IntConstList.LockList do
  1104. try
  1105. for i := 0 to Count - 1 do
  1106. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  1107. Exit(True);
  1108. Result := false;
  1109. finally
  1110. IntConstList.UnlockList;
  1111. end;
  1112. end;
  1113. { TPropFixup }
  1114. // Tainted. TPropFixup is being removed.
  1115. Type
  1116. TInitHandler = Class(TObject)
  1117. AHandler : TInitComponentHandler;
  1118. AClass : TComponentClass;
  1119. end;
  1120. {$ifndef i8086}
  1121. type
  1122. TCodePtrList = TList;
  1123. {$endif i8086}
  1124. Var
  1125. InitHandlerList : TList;
  1126. FindGlobalComponentList : TCodePtrList;
  1127. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  1128. begin
  1129. if not(assigned(FindGlobalComponentList)) then
  1130. FindGlobalComponentList:=TCodePtrList.Create;
  1131. if FindGlobalComponentList.IndexOf(CodePointer(AFindGlobalComponent))<0 then
  1132. FindGlobalComponentList.Add(CodePointer(AFindGlobalComponent));
  1133. end;
  1134. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  1135. begin
  1136. if assigned(FindGlobalComponentList) then
  1137. FindGlobalComponentList.Remove(CodePointer(AFindGlobalComponent));
  1138. end;
  1139. function FindGlobalComponent(const Name: string): TComponent;
  1140. var
  1141. i : sizeint;
  1142. begin
  1143. FindGlobalComponent:=nil;
  1144. if assigned(FindGlobalComponentList) then
  1145. begin
  1146. for i:=FindGlobalComponentList.Count-1 downto 0 do
  1147. begin
  1148. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  1149. if assigned(FindGlobalComponent) then
  1150. break;
  1151. end;
  1152. end;
  1153. end;
  1154. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  1155. Var
  1156. I : Integer;
  1157. H: TInitHandler;
  1158. begin
  1159. If (InitHandlerList=Nil) then
  1160. InitHandlerList:=TList.Create;
  1161. H:=TInitHandler.Create;
  1162. H.Aclass:=ComponentClass;
  1163. H.AHandler:=Handler;
  1164. try
  1165. With InitHandlerList do
  1166. begin
  1167. I:=0;
  1168. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  1169. Inc(I);
  1170. { override? }
  1171. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  1172. begin
  1173. TInitHandler(Items[I]).AHandler:=Handler;
  1174. H.Free;
  1175. end
  1176. else
  1177. InitHandlerList.Insert(I,H);
  1178. end;
  1179. except
  1180. H.Free;
  1181. raise;
  1182. end;
  1183. end;
  1184. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  1185. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  1186. var
  1187. ResStream : TResourceStream;
  1188. ResID : TFPResourceHandle;
  1189. begin
  1190. if Inst=0 then
  1191. Inst:=HInstance;
  1192. ResId:=System.FindResource(Inst, Res, RT_RCDATA);
  1193. result:=ResID<>0;
  1194. try
  1195. if Result then
  1196. begin
  1197. ResStream:=TResourceStream.Create(Inst,Res,RT_RCDATA);
  1198. try
  1199. Component:=ResStream.ReadComponent(Component);
  1200. finally
  1201. ResStream.Free;
  1202. end;
  1203. end;
  1204. except
  1205. on EResNotFound do
  1206. result:=false;
  1207. end;
  1208. end;
  1209. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  1210. function doinit(_class : TClass) : boolean;
  1211. begin
  1212. result:=false;
  1213. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  1214. exit;
  1215. result:=doinit(_class.ClassParent);
  1216. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  1217. end;
  1218. begin
  1219. {$ifdef FPC_HAS_FEATURE_THREADING}
  1220. GlobalNameSpace.BeginWrite;
  1221. try
  1222. {$endif}
  1223. result:=doinit(Instance.ClassType);
  1224. {$ifdef FPC_HAS_FEATURE_THREADING}
  1225. finally
  1226. GlobalNameSpace.EndWrite;
  1227. end;
  1228. {$endif}
  1229. end;
  1230. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  1231. Var
  1232. I : Integer;
  1233. begin
  1234. I:=0;
  1235. if not Assigned(InitHandlerList) then begin
  1236. Result := True;
  1237. Exit;
  1238. end;
  1239. Result:=False;
  1240. With InitHandlerList do
  1241. begin
  1242. I:=0;
  1243. // Instance is the normally the lowest one, so that one should be used when searching.
  1244. While Not result and (I<Count) do
  1245. begin
  1246. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  1247. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  1248. Inc(I);
  1249. end;
  1250. end;
  1251. end;
  1252. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  1253. begin
  1254. Result:=ReadComponentRes(ResName,Instance)=Instance;
  1255. end;
  1256. function SysReadComponentRes(HInstance : THandle; const ResName: String; Instance: TComponent): TComponent;
  1257. Var
  1258. H : TFPResourceHandle;
  1259. begin
  1260. { Windows unit also has a FindResource function, use the one from
  1261. system unit here. }
  1262. H:=system.FindResource(HInstance,ResName,RT_RCDATA);
  1263. if (PtrInt(H)=0) then
  1264. Result:=Nil
  1265. else
  1266. With TResourceStream.Create(HInstance,ResName,RT_RCDATA) do
  1267. try
  1268. Result:=ReadComponent(Instance);
  1269. Finally
  1270. Free;
  1271. end;
  1272. end;
  1273. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  1274. begin
  1275. Result:=SysReadComponentRes(Hinstance,Resname,Instance);
  1276. end;
  1277. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  1278. begin
  1279. Result:=SysReadComponentRes(Hinstance,ResName,Nil);
  1280. end;
  1281. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  1282. var
  1283. FileStream: TStream;
  1284. begin
  1285. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  1286. try
  1287. Result := FileStream.ReadComponentRes(Instance);
  1288. finally
  1289. FileStream.Free;
  1290. end;
  1291. end;
  1292. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  1293. var
  1294. FileStream: TStream;
  1295. begin
  1296. FileStream := TFileStream.Create(FileName, fmCreate);
  1297. try
  1298. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  1299. finally
  1300. FileStream.Free;
  1301. end;
  1302. end;
  1303. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  1304. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  1305. Var
  1306. P : Integer;
  1307. CM : Boolean;
  1308. begin
  1309. P:=Pos('.',APath);
  1310. CM:=False;
  1311. If (P=0) then
  1312. begin
  1313. If CStyle then
  1314. begin
  1315. P:=Pos('->',APath);
  1316. CM:=P<>0;
  1317. end;
  1318. If (P=0) Then
  1319. P:=Length(APath)+1;
  1320. end;
  1321. Result:=Copy(APath,1,P-1);
  1322. Delete(APath,1,P+Ord(CM));
  1323. end;
  1324. Var
  1325. C : TComponent;
  1326. S : String;
  1327. begin
  1328. If (APath='') then
  1329. Result:=Nil
  1330. else
  1331. begin
  1332. Result:=Root;
  1333. While (APath<>'') And (Result<>Nil) do
  1334. begin
  1335. C:=Result;
  1336. S:=Uppercase(GetNextName);
  1337. Result:=C.FindComponent(S);
  1338. If (Result=Nil) And (S='OWNER') then
  1339. Result:=C;
  1340. end;
  1341. end;
  1342. end;
  1343. {$ifdef FPC_HAS_FEATURE_THREADING}
  1344. threadvar
  1345. {$else}
  1346. var
  1347. {$endif}
  1348. GlobalLoaded, GlobalLists: TFpList;
  1349. procedure BeginGlobalLoading;
  1350. begin
  1351. if not Assigned(GlobalLists) then
  1352. GlobalLists := TFpList.Create;
  1353. GlobalLists.Add(GlobalLoaded);
  1354. GlobalLoaded := TFpList.Create;
  1355. end;
  1356. { Notify all global components that they have been loaded completely }
  1357. procedure NotifyGlobalLoading;
  1358. var
  1359. i: Integer;
  1360. begin
  1361. for i := 0 to GlobalLoaded.Count - 1 do
  1362. TComponent(GlobalLoaded[i]).Loaded;
  1363. end;
  1364. procedure EndGlobalLoading;
  1365. begin
  1366. { Free the memory occupied by BeginGlobalLoading }
  1367. GlobalLoaded.Free;
  1368. GlobalLoaded := TFpList(GlobalLists.Last);
  1369. GlobalLists.Delete(GlobalLists.Count - 1);
  1370. if GlobalLists.Count = 0 then
  1371. begin
  1372. GlobalLists.Free;
  1373. GlobalLists := nil;
  1374. end;
  1375. end;
  1376. function CollectionsEqual(C1, C2: TCollection): Boolean;
  1377. begin
  1378. // !!!: Implement this
  1379. CollectionsEqual:=false;
  1380. end;
  1381. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  1382. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  1383. var
  1384. w : twriter;
  1385. begin
  1386. w:=twriter.create(s,4096);
  1387. try
  1388. w.root:=o;
  1389. w.flookuproot:=o;
  1390. w.writecollection(c);
  1391. finally
  1392. w.free;
  1393. end;
  1394. end;
  1395. var
  1396. s1,s2 : tmemorystream;
  1397. begin
  1398. result:=false;
  1399. if (c1.classtype<>c2.classtype) or
  1400. (c1.count<>c2.count) then
  1401. exit;
  1402. if c1.count = 0 then
  1403. begin
  1404. result:= true;
  1405. exit;
  1406. end;
  1407. s1:=tmemorystream.create;
  1408. try
  1409. s2:=tmemorystream.create;
  1410. try
  1411. stream_collection(s1,c1,owner1);
  1412. stream_collection(s2,c2,owner2);
  1413. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  1414. finally
  1415. s2.free;
  1416. end;
  1417. finally
  1418. s1.free;
  1419. end;
  1420. end;
  1421. { Object conversion routines }
  1422. type
  1423. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  1424. function CharToOrd(var P: Pointer): Cardinal;
  1425. begin
  1426. result:= ord(pchar(P)^);
  1427. inc(pchar(P));
  1428. end;
  1429. function WideCharToOrd(var P: Pointer): Cardinal;
  1430. begin
  1431. result:= ord(pwidechar(P)^);
  1432. inc(pwidechar(P));
  1433. end;
  1434. function Utf8ToOrd(var P:Pointer): Cardinal;
  1435. begin
  1436. // Should also check for illegal utf8 combinations
  1437. Result := Ord(PChar(P)^);
  1438. Inc(P);
  1439. if (Result and $80) <> 0 then
  1440. if (Ord(Result) and %11100000) = %11000000 then begin
  1441. Result := ((Result and %00011111) shl 6)
  1442. or (ord(PChar(P)^) and %00111111);
  1443. Inc(P);
  1444. end else if (Ord(Result) and %11110000) = %11100000 then begin
  1445. Result := ((Result and %00011111) shl 12)
  1446. or ((ord(PChar(P)^) and %00111111) shl 6)
  1447. or (ord((PChar(P)+1)^) and %00111111);
  1448. Inc(P,2);
  1449. end else begin
  1450. Result := ((ord(Result) and %00011111) shl 18)
  1451. or ((ord(PChar(P)^) and %00111111) shl 12)
  1452. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  1453. or (ord((PChar(P)+2)^) and %00111111);
  1454. Inc(P,3);
  1455. end;
  1456. end;
  1457. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  1458. var
  1459. Version: TBinaryObjectReader.TBOVersion;
  1460. procedure OutStr(s: String);
  1461. begin
  1462. if Length(s) > 0 then
  1463. Output.Write(s[1], Length(s));
  1464. end;
  1465. procedure OutLn(s: String);
  1466. begin
  1467. OutStr(s + LineEnding);
  1468. end;
  1469. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  1470. UseBytes: boolean = false);
  1471. var
  1472. res, NewStr: String;
  1473. w: Cardinal;
  1474. InString, NewInString: Boolean;
  1475. begin
  1476. if p = nil then begin
  1477. res:= '''''';
  1478. end
  1479. else
  1480. begin
  1481. res := '';
  1482. InString := False;
  1483. while P < LastP do
  1484. begin
  1485. NewInString := InString;
  1486. w := CharToOrdfunc(P);
  1487. if w = ord('''') then
  1488. begin //quote char
  1489. if not InString then
  1490. NewInString := True;
  1491. NewStr := '''''';
  1492. end
  1493. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  1494. begin //printable ascii or bytes
  1495. if not InString then
  1496. NewInString := True;
  1497. NewStr := char(w);
  1498. end
  1499. else
  1500. begin //ascii control chars, non ascii
  1501. if InString then
  1502. NewInString := False;
  1503. NewStr := '#' + IntToStr(w);
  1504. end;
  1505. if NewInString <> InString then
  1506. begin
  1507. NewStr := '''' + NewStr;
  1508. InString := NewInString;
  1509. end;
  1510. res := res + NewStr;
  1511. end;
  1512. if InString then
  1513. res := res + '''';
  1514. end;
  1515. OutStr(res);
  1516. end;
  1517. procedure OutString(s: String);
  1518. begin
  1519. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  1520. end;
  1521. procedure OutWString(W: WideString);
  1522. begin
  1523. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1524. end;
  1525. procedure OutUString(W: UnicodeString);
  1526. begin
  1527. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1528. end;
  1529. procedure OutUtf8Str(s: String);
  1530. begin
  1531. if Encoding=oteLFM then
  1532. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd)
  1533. else
  1534. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  1535. end;
  1536. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1537. begin
  1538. Result:=Input.ReadWord;
  1539. Result:=LEtoN(Result);
  1540. end;
  1541. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1542. begin
  1543. Result:=Input.ReadDWord;
  1544. Result:=LEtoN(Result);
  1545. end;
  1546. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1547. begin
  1548. Input.ReadBuffer(Result,sizeof(Result));
  1549. Result:=LEtoN(Result);
  1550. end;
  1551. {$ifndef FPUNONE}
  1552. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1553. function ExtendedToDouble(e : pointer) : double;
  1554. var mant : qword;
  1555. exp : smallint;
  1556. sign : boolean;
  1557. d : qword;
  1558. begin
  1559. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  1560. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  1561. mant:=LEtoN(mant);
  1562. exp:=LetoN(word(exp));
  1563. sign:=(exp and $8000)<>0;
  1564. if sign then exp:=exp and $7FFF;
  1565. case exp of
  1566. 0 : mant:=0; //if denormalized, value is too small for double,
  1567. //so it's always zero
  1568. $7FFF : exp:=2047 //either infinity or NaN
  1569. else
  1570. begin
  1571. dec(exp,16383-1023);
  1572. if (exp>=-51) and (exp<=0) then //can be denormalized
  1573. begin
  1574. mant:=mant shr (-exp);
  1575. exp:=0;
  1576. end
  1577. else
  1578. if (exp<-51) or (exp>2046) then //exponent too large.
  1579. begin
  1580. Result:=0;
  1581. exit;
  1582. end
  1583. else //normalized value
  1584. mant:=mant shl 1; //hide most significant bit
  1585. end;
  1586. end;
  1587. d:=word(exp);
  1588. d:=d shl 52;
  1589. mant:=mant shr 12;
  1590. d:=d or mant;
  1591. if sign then d:=d or $8000000000000000;
  1592. Result:=pdouble(@d)^;
  1593. end;
  1594. {$ENDIF}
  1595. {$endif}
  1596. function ReadInt(ValueType: TValueType): Int64;
  1597. begin
  1598. case ValueType of
  1599. vaInt8: Result := ShortInt(Input.ReadByte);
  1600. vaInt16: Result := SmallInt(ReadWord);
  1601. vaInt32: Result := LongInt(ReadDWord);
  1602. vaInt64: Result := Int64(ReadQWord);
  1603. end;
  1604. end;
  1605. function ReadInt: Int64;
  1606. begin
  1607. Result := ReadInt(TValueType(Input.ReadByte));
  1608. end;
  1609. {$ifndef FPUNONE}
  1610. function ReadExtended : extended;
  1611. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1612. var ext : array[0..9] of byte;
  1613. {$ENDIF}
  1614. begin
  1615. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1616. Input.ReadBuffer(ext[0],10);
  1617. Result:=ExtendedToDouble(@(ext[0]));
  1618. {$ELSE}
  1619. Input.ReadBuffer(Result,sizeof(Result));
  1620. {$ENDIF}
  1621. end;
  1622. {$endif}
  1623. function ReadSStr: String;
  1624. var
  1625. len: Byte;
  1626. begin
  1627. len := Input.ReadByte;
  1628. SetLength(Result, len);
  1629. if (len > 0) then
  1630. Input.ReadBuffer(Result[1], len);
  1631. end;
  1632. function ReadLStr: String;
  1633. var
  1634. len: DWord;
  1635. begin
  1636. len := ReadDWord;
  1637. SetLength(Result, len);
  1638. if (len > 0) then
  1639. Input.ReadBuffer(Result[1], len);
  1640. end;
  1641. function ReadWStr: WideString;
  1642. var
  1643. len: DWord;
  1644. {$IFDEF ENDIAN_BIG}
  1645. i : integer;
  1646. {$ENDIF}
  1647. begin
  1648. len := ReadDWord;
  1649. SetLength(Result, len);
  1650. if (len > 0) then
  1651. begin
  1652. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1653. {$IFDEF ENDIAN_BIG}
  1654. for i:=1 to len do
  1655. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1656. {$ENDIF}
  1657. end;
  1658. end;
  1659. function ReadUStr: UnicodeString;
  1660. var
  1661. len: DWord;
  1662. {$IFDEF ENDIAN_BIG}
  1663. i : integer;
  1664. {$ENDIF}
  1665. begin
  1666. len := ReadDWord;
  1667. SetLength(Result, len);
  1668. if (len > 0) then
  1669. begin
  1670. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1671. {$IFDEF ENDIAN_BIG}
  1672. for i:=1 to len do
  1673. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1674. {$ENDIF}
  1675. end;
  1676. end;
  1677. procedure ReadPropList(indent: String);
  1678. procedure ProcessValue(ValueType: TValueType; Indent: String);
  1679. procedure ProcessBinary;
  1680. var
  1681. ToDo, DoNow, i: LongInt;
  1682. lbuf: array[0..31] of Byte;
  1683. s: String;
  1684. begin
  1685. ToDo := ReadDWord;
  1686. OutLn('{');
  1687. while ToDo > 0 do begin
  1688. DoNow := ToDo;
  1689. if DoNow > 32 then DoNow := 32;
  1690. Dec(ToDo, DoNow);
  1691. s := Indent + ' ';
  1692. Input.ReadBuffer(lbuf, DoNow);
  1693. for i := 0 to DoNow - 1 do
  1694. s := s + IntToHex(lbuf[i], 2);
  1695. OutLn(s);
  1696. end;
  1697. OutLn(indent + '}');
  1698. end;
  1699. var
  1700. s: String;
  1701. { len: LongInt; }
  1702. IsFirst: Boolean;
  1703. {$ifndef FPUNONE}
  1704. ext: Extended;
  1705. {$endif}
  1706. begin
  1707. case ValueType of
  1708. vaList: begin
  1709. OutStr('(');
  1710. IsFirst := True;
  1711. while True do begin
  1712. ValueType := TValueType(Input.ReadByte);
  1713. if ValueType = vaNull then break;
  1714. if IsFirst then begin
  1715. OutLn('');
  1716. IsFirst := False;
  1717. end;
  1718. OutStr(Indent + ' ');
  1719. ProcessValue(ValueType, Indent + ' ');
  1720. end;
  1721. OutLn(Indent + ')');
  1722. end;
  1723. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  1724. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  1725. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  1726. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  1727. {$ifndef FPUNONE}
  1728. vaExtended: begin
  1729. ext:=ReadExtended;
  1730. Str(ext,S);// Do not use localized strings.
  1731. OutLn(S);
  1732. end;
  1733. {$endif}
  1734. vaString: begin
  1735. OutString(ReadSStr);
  1736. OutLn('');
  1737. end;
  1738. vaIdent: OutLn(ReadSStr);
  1739. vaFalse: OutLn('False');
  1740. vaTrue: OutLn('True');
  1741. vaBinary: ProcessBinary;
  1742. vaSet: begin
  1743. OutStr('[');
  1744. IsFirst := True;
  1745. while True do begin
  1746. s := ReadSStr;
  1747. if Length(s) = 0 then break;
  1748. if not IsFirst then OutStr(', ');
  1749. IsFirst := False;
  1750. OutStr(s);
  1751. end;
  1752. OutLn(']');
  1753. end;
  1754. vaLString:
  1755. begin
  1756. OutString(ReadLStr);
  1757. OutLn('');
  1758. end;
  1759. vaWString:
  1760. begin
  1761. OutWString(ReadWStr);
  1762. OutLn('');
  1763. end;
  1764. vaUString:
  1765. begin
  1766. OutWString(ReadWStr);
  1767. OutLn('');
  1768. end;
  1769. vaNil:
  1770. OutLn('nil');
  1771. vaCollection: begin
  1772. OutStr('<');
  1773. while Input.ReadByte <> 0 do begin
  1774. OutLn(Indent);
  1775. Input.Seek(-1, soFromCurrent);
  1776. OutStr(indent + ' item');
  1777. ValueType := TValueType(Input.ReadByte);
  1778. if ValueType <> vaList then
  1779. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1780. OutLn('');
  1781. ReadPropList(indent + ' ');
  1782. OutStr(indent + ' end');
  1783. end;
  1784. OutLn('>');
  1785. end;
  1786. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1787. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1788. vaDate: begin OutLn('!!Date!!'); exit end;}
  1789. vaUTF8String: begin
  1790. OutUtf8Str(ReadLStr);
  1791. OutLn('');
  1792. end;
  1793. else
  1794. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1795. end;
  1796. end;
  1797. begin
  1798. while Input.ReadByte <> 0 do begin
  1799. Input.Seek(-1, soFromCurrent);
  1800. OutStr(indent + ReadSStr + ' = ');
  1801. ProcessValue(TValueType(Input.ReadByte), Indent);
  1802. end;
  1803. end;
  1804. procedure ReadObject(indent: String);
  1805. var
  1806. b: Byte;
  1807. ObjUnitName, ObjClassName, ObjName: String;
  1808. ChildPos: LongInt;
  1809. ValueType: TValueType;
  1810. p: SizeInt;
  1811. begin
  1812. // Check for FilerFlags
  1813. b := Input.ReadByte;
  1814. if (b and $f0) = $f0 then begin
  1815. if (b and 2) <> 0 then ChildPos := ReadInt;
  1816. end else begin
  1817. b := 0;
  1818. Input.Seek(-1, soFromCurrent);
  1819. end;
  1820. ObjUnitName:='';
  1821. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  1822. begin
  1823. ValueType := TValueType(Input.ReadByte);
  1824. if ValueType=vaString then
  1825. ObjClassName := ReadSStr
  1826. else
  1827. ObjClassName := ReadLStr;
  1828. p:=Pos(TBinaryObjectReader.UnitnameSeparator,ObjClassName);
  1829. if p>0 then
  1830. begin
  1831. ObjUnitName:=copy(ObjClassName,1,p-1);
  1832. System.Delete(ObjClassName,1,p);
  1833. end;
  1834. end else
  1835. ObjClassName := ReadSStr;
  1836. ObjName := ReadSStr;
  1837. OutStr(Indent);
  1838. if (b and 1) <> 0 then
  1839. OutStr('inherited')
  1840. else if (b and 4) <> 0 then
  1841. OutStr('inline')
  1842. else
  1843. OutStr('object');
  1844. OutStr(' ');
  1845. if ObjName <> '' then
  1846. OutStr(ObjName + ': ');
  1847. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  1848. begin
  1849. OutStr(ObjUnitName);
  1850. OutStr('/');
  1851. end;
  1852. OutStr(ObjClassName);
  1853. if (b and 2) <> 0 then
  1854. OutStr('[' + IntToStr(ChildPos) + ']');
  1855. OutLn('');
  1856. ReadPropList(indent + ' ');
  1857. while Input.ReadByte <> 0 do begin
  1858. Input.Seek(-1, soFromCurrent);
  1859. ReadObject(indent + ' ');
  1860. end;
  1861. OutLn(indent + 'end');
  1862. end;
  1863. var
  1864. Signature: DWord;
  1865. begin
  1866. Signature:=Input.ReadDWord;
  1867. if Signature = DWord(unaligned(FilerSignature1)) then
  1868. Version:=TBinaryObjectReader.TBOVersion.boVersion1
  1869. else if Signature = DWord(unaligned(FilerSignature)) then
  1870. Version:=TBinaryObjectReader.TBOVersion.boVersion0
  1871. else
  1872. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1873. ReadObject('');
  1874. end;
  1875. procedure ObjectBinaryToText(Input, Output: TStream);
  1876. begin
  1877. ObjectBinaryToText(Input,Output,oteDFM);
  1878. end;
  1879. procedure ObjectTextToBinary(Input, Output: TStream);
  1880. var
  1881. parser: TParser;
  1882. Version: TBinaryObjectReader.TBOVersion;
  1883. StartPos: Int64;
  1884. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1885. begin
  1886. w:=NtoLE(w);
  1887. Output.WriteWord(w);
  1888. end;
  1889. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1890. begin
  1891. lw:=NtoLE(lw);
  1892. Output.WriteDWord(lw);
  1893. end;
  1894. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1895. begin
  1896. qw:=NtoLE(qw);
  1897. Output.WriteBuffer(qw,sizeof(qword));
  1898. end;
  1899. {$ifndef FPUNONE}
  1900. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1901. procedure DoubleToExtended(d : double; e : pointer);
  1902. var mant : qword;
  1903. exp : smallint;
  1904. sign : boolean;
  1905. begin
  1906. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1907. exp :=(qword(d) shr 52) and $7FF;
  1908. sign:=(qword(d) and $8000000000000000)<>0;
  1909. case exp of
  1910. 0 : begin
  1911. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1912. begin
  1913. exp:=16383-1022;
  1914. while (mant and $8000000000000000)=0 do
  1915. begin
  1916. dec(exp);
  1917. mant:=mant shl 1;
  1918. end;
  1919. dec(exp); //don't shift, most significant bit is not hidden in extended
  1920. end;
  1921. end;
  1922. 2047 : exp:=$7FFF //either infinity or NaN
  1923. else
  1924. begin
  1925. inc(exp,16383-1023);
  1926. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1927. end;
  1928. end;
  1929. if sign then exp:=exp or $8000;
  1930. mant:=NtoLE(mant);
  1931. exp:=NtoLE(word(exp));
  1932. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1933. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1934. end;
  1935. {$ENDIF}
  1936. procedure WriteExtended(const e : extended);
  1937. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1938. var ext : array[0..9] of byte;
  1939. {$ENDIF}
  1940. begin
  1941. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1942. DoubleToExtended(e,@(ext[0]));
  1943. Output.WriteBuffer(ext[0],10);
  1944. {$ELSE}
  1945. Output.WriteBuffer(e,sizeof(e));
  1946. {$ENDIF}
  1947. end;
  1948. {$endif}
  1949. procedure WriteSString(const s: String);
  1950. var size : byte;
  1951. begin
  1952. if length(s)>255 then size:=255
  1953. else size:=length(s);
  1954. Output.WriteByte(size);
  1955. if Length(s) > 0 then
  1956. Output.WriteBuffer(s[1], size);
  1957. end;
  1958. procedure WriteLString(Const s: String);
  1959. begin
  1960. WriteDWord(Length(s));
  1961. if Length(s) > 0 then
  1962. Output.WriteBuffer(s[1], Length(s));
  1963. end;
  1964. procedure WriteSorLString(Const s: String);
  1965. begin
  1966. if length(s)<256 then
  1967. begin
  1968. Output.WriteByte(Ord(vaString));
  1969. WriteSString(s);
  1970. end else begin
  1971. Output.WriteByte(Ord(vaLString));
  1972. WriteSString(s);
  1973. end;
  1974. end;
  1975. procedure WriteWString(Const s: WideString);
  1976. var len : longword;
  1977. {$IFDEF ENDIAN_BIG}
  1978. i : integer;
  1979. ws : widestring;
  1980. {$ENDIF}
  1981. begin
  1982. len:=Length(s);
  1983. WriteDWord(len);
  1984. if len > 0 then
  1985. begin
  1986. {$IFDEF ENDIAN_BIG}
  1987. setlength(ws,len);
  1988. for i:=1 to len do
  1989. ws[i]:=widechar(SwapEndian(word(s[i])));
  1990. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1991. {$ELSE}
  1992. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1993. {$ENDIF}
  1994. end;
  1995. end;
  1996. procedure WriteInteger(value: Int64);
  1997. begin
  1998. if (value >= -128) and (value <= 127) then begin
  1999. Output.WriteByte(Ord(vaInt8));
  2000. Output.WriteByte(byte(value));
  2001. end else if (value >= -32768) and (value <= 32767) then begin
  2002. Output.WriteByte(Ord(vaInt16));
  2003. WriteWord(word(value));
  2004. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  2005. Output.WriteByte(Ord(vaInt32));
  2006. WriteDWord(longword(value));
  2007. end else begin
  2008. Output.WriteByte(ord(vaInt64));
  2009. WriteQWord(qword(value));
  2010. end;
  2011. end;
  2012. procedure ProcessWideString(const left : widestring);
  2013. var ws : widestring;
  2014. begin
  2015. ws:=left+parser.TokenWideString;
  2016. while parser.NextToken = '+' do
  2017. begin
  2018. parser.NextToken; // Get next string fragment
  2019. if not (parser.Token in [toString,toWString]) then
  2020. parser.CheckToken(toWString);
  2021. ws:=ws+parser.TokenWideString;
  2022. end;
  2023. Output.WriteByte(Ord(vaWstring));
  2024. WriteWString(ws);
  2025. end;
  2026. procedure ProcessProperty; forward;
  2027. procedure ProcessValue;
  2028. var
  2029. {$ifndef FPUNONE}
  2030. flt: Extended;
  2031. {$endif}
  2032. s: String;
  2033. stream: TMemoryStream;
  2034. begin
  2035. case parser.Token of
  2036. toInteger:
  2037. begin
  2038. WriteInteger(parser.TokenInt);
  2039. parser.NextToken;
  2040. end;
  2041. {$ifndef FPUNONE}
  2042. toFloat:
  2043. begin
  2044. Output.WriteByte(Ord(vaExtended));
  2045. flt := Parser.TokenFloat;
  2046. WriteExtended(flt);
  2047. parser.NextToken;
  2048. end;
  2049. {$endif}
  2050. toString:
  2051. begin
  2052. s := parser.TokenString;
  2053. while parser.NextToken = '+' do
  2054. begin
  2055. parser.NextToken; // Get next string fragment
  2056. case parser.Token of
  2057. toString : s:=s+parser.TokenString;
  2058. toWString : begin
  2059. ProcessWideString(WideString(s));
  2060. exit;
  2061. end
  2062. else parser.CheckToken(toString);
  2063. end;
  2064. end;
  2065. if (length(S)>255) then
  2066. begin
  2067. Output.WriteByte(Ord(vaLString));
  2068. WriteLString(S);
  2069. end
  2070. else
  2071. begin
  2072. Output.WriteByte(Ord(vaString));
  2073. WriteSString(s);
  2074. end;
  2075. end;
  2076. toWString:
  2077. ProcessWideString('');
  2078. toSymbol:
  2079. begin
  2080. if CompareText(parser.TokenString, 'True') = 0 then
  2081. Output.WriteByte(Ord(vaTrue))
  2082. else if CompareText(parser.TokenString, 'False') = 0 then
  2083. Output.WriteByte(Ord(vaFalse))
  2084. else if CompareText(parser.TokenString, 'nil') = 0 then
  2085. Output.WriteByte(Ord(vaNil))
  2086. else
  2087. begin
  2088. Output.WriteByte(Ord(vaIdent));
  2089. WriteSString(parser.TokenComponentIdent);
  2090. end;
  2091. Parser.NextToken;
  2092. end;
  2093. // Set
  2094. '[':
  2095. begin
  2096. parser.NextToken;
  2097. Output.WriteByte(Ord(vaSet));
  2098. if parser.Token <> ']' then
  2099. while True do
  2100. begin
  2101. parser.CheckToken(toSymbol);
  2102. WriteSString(parser.TokenString);
  2103. parser.NextToken;
  2104. if parser.Token = ']' then
  2105. break;
  2106. parser.CheckToken(',');
  2107. parser.NextToken;
  2108. end;
  2109. Output.WriteByte(0);
  2110. parser.NextToken;
  2111. end;
  2112. // List
  2113. '(':
  2114. begin
  2115. parser.NextToken;
  2116. Output.WriteByte(Ord(vaList));
  2117. while parser.Token <> ')' do
  2118. ProcessValue;
  2119. Output.WriteByte(0);
  2120. parser.NextToken;
  2121. end;
  2122. // Collection
  2123. '<':
  2124. begin
  2125. parser.NextToken;
  2126. Output.WriteByte(Ord(vaCollection));
  2127. while parser.Token <> '>' do
  2128. begin
  2129. parser.CheckTokenSymbol('item');
  2130. parser.NextToken;
  2131. // ConvertOrder
  2132. Output.WriteByte(Ord(vaList));
  2133. while not parser.TokenSymbolIs('end') do
  2134. ProcessProperty;
  2135. parser.NextToken; // Skip 'end'
  2136. Output.WriteByte(0);
  2137. end;
  2138. Output.WriteByte(0);
  2139. parser.NextToken;
  2140. end;
  2141. // Binary data
  2142. '{':
  2143. begin
  2144. Output.WriteByte(Ord(vaBinary));
  2145. stream := TMemoryStream.Create;
  2146. try
  2147. parser.HexToBinary(stream);
  2148. WriteDWord(stream.Size);
  2149. Output.WriteBuffer(Stream.Memory^, stream.Size);
  2150. finally
  2151. stream.Free;
  2152. end;
  2153. parser.NextToken;
  2154. end;
  2155. else
  2156. parser.Error(SInvalidProperty);
  2157. end;
  2158. end;
  2159. procedure ProcessProperty;
  2160. var
  2161. name: String;
  2162. begin
  2163. // Get name of property
  2164. parser.CheckToken(toSymbol);
  2165. name := parser.TokenString;
  2166. while True do begin
  2167. parser.NextToken;
  2168. if parser.Token <> '.' then break;
  2169. parser.NextToken;
  2170. parser.CheckToken(toSymbol);
  2171. name := name + '.' + parser.TokenString;
  2172. end;
  2173. WriteSString(name);
  2174. parser.CheckToken('=');
  2175. parser.NextToken;
  2176. ProcessValue;
  2177. end;
  2178. procedure ProcessObject(Root: boolean);
  2179. var
  2180. Flags: Byte;
  2181. ObjectName, ObjUnitName, ObjClassName: String;
  2182. ChildPos: Integer;
  2183. begin
  2184. if parser.TokenSymbolIs('OBJECT') then
  2185. Flags :=0 { IsInherited := False }
  2186. else begin
  2187. if parser.TokenSymbolIs('INHERITED') then
  2188. Flags := 1 { IsInherited := True; }
  2189. else begin
  2190. parser.CheckTokenSymbol('INLINE');
  2191. Flags := 4;
  2192. end;
  2193. end;
  2194. parser.NextToken;
  2195. parser.CheckToken(toSymbol);
  2196. ObjectName := '';
  2197. ObjUnitName := '';
  2198. ObjClassName := parser.TokenString;
  2199. parser.NextToken;
  2200. if parser.Token = '/' then begin
  2201. ObjUnitName := ObjClassName;
  2202. parser.NextToken;
  2203. parser.CheckToken(toSymbol);
  2204. ObjClassName := parser.TokenString;
  2205. parser.NextToken;
  2206. end else if parser.Token = ':' then begin
  2207. parser.NextToken;
  2208. parser.CheckToken(toSymbol);
  2209. ObjectName := ObjClassName;
  2210. ObjClassName := parser.TokenString;
  2211. parser.NextToken;
  2212. if parser.Token = '/' then begin
  2213. ObjUnitName := ObjClassName;
  2214. parser.NextToken;
  2215. parser.CheckToken(toSymbol);
  2216. ObjClassName := parser.TokenString;
  2217. parser.NextToken;
  2218. end;
  2219. if parser.Token = '[' then begin
  2220. parser.NextToken;
  2221. ChildPos := parser.TokenInt;
  2222. parser.NextToken;
  2223. parser.CheckToken(']');
  2224. parser.NextToken;
  2225. Flags := Flags or 2;
  2226. end;
  2227. end;
  2228. if Root then
  2229. begin
  2230. if (ObjUnitName<>'') then
  2231. Version:=TBinaryObjectReader.TBOVersion.boVersion1;
  2232. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  2233. Output.WriteBuffer(FilerSignature1[1], length(FilerSignature1))
  2234. else
  2235. Output.WriteBuffer(FilerSignature[1], length(FilerSignature));
  2236. end;
  2237. if Flags <> 0 then begin
  2238. Output.WriteByte($f0 or Flags);
  2239. if (Flags and 2) <> 0 then
  2240. WriteInteger(ChildPos);
  2241. end;
  2242. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  2243. WriteSorLString(ObjUnitName+TBinaryObjectReader.UnitnameSeparator+ObjClassName)
  2244. else
  2245. WriteSString(ObjClassName);
  2246. WriteSString(ObjectName);
  2247. // Convert property list
  2248. while not (parser.TokenSymbolIs('END') or
  2249. parser.TokenSymbolIs('OBJECT') or
  2250. parser.TokenSymbolIs('INHERITED') or
  2251. parser.TokenSymbolIs('INLINE')) do
  2252. ProcessProperty;
  2253. Output.WriteByte(0); // Terminate property list
  2254. // Convert child objects
  2255. while not parser.TokenSymbolIs('END') do ProcessObject(false);
  2256. parser.NextToken; // Skip end token
  2257. Output.WriteByte(0); // Terminate property list
  2258. end;
  2259. begin
  2260. Version:=TBinaryObjectReader.TBOVersion.boVersion0;
  2261. parser := TParser.Create(Input);
  2262. try
  2263. StartPos:=Output.Position;
  2264. ProcessObject(true);
  2265. finally
  2266. parser.Free;
  2267. end;
  2268. end;
  2269. procedure ObjectResourceToText(Input, Output: TStream);
  2270. begin
  2271. Input.ReadResHeader;
  2272. ObjectBinaryToText(Input, Output);
  2273. end;
  2274. procedure ObjectTextToResource(Input, Output: TStream);
  2275. var
  2276. StartPos, FixupInfo: LongInt;
  2277. parser: TParser;
  2278. name: String;
  2279. begin
  2280. // Get form type name
  2281. StartPos := Input.Position;
  2282. parser := TParser.Create(Input);
  2283. try
  2284. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  2285. parser.NextToken;
  2286. parser.CheckToken(toSymbol);
  2287. parser.NextToken;
  2288. parser.CheckToken(':');
  2289. parser.NextToken;
  2290. parser.CheckToken(toSymbol);
  2291. name := parser.TokenString;
  2292. finally
  2293. parser.Free;
  2294. Input.Position := StartPos;
  2295. end;
  2296. name := UpperCase(name);
  2297. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  2298. ObjectTextToBinary(Input, Output); // Convert the stuff!
  2299. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  2300. end;
  2301. { Utility routines }
  2302. Function IfThen(AValue: Boolean; const ATrue: TStringList; const AFalse: TStringList = nil): TStringList; overload;
  2303. begin
  2304. if avalue then
  2305. result:=atrue
  2306. else
  2307. result:=afalse;
  2308. end;
  2309. function LineStart(Buffer, BufPos: PChar): PChar;
  2310. begin
  2311. Result := BufPos;
  2312. while Result > Buffer do begin
  2313. Dec(Result);
  2314. if Result[0] = #10 then break;
  2315. end;
  2316. end;
  2317. procedure CommonInit;
  2318. begin
  2319. {$ifdef FPC_HAS_FEATURE_THREADING}
  2320. SynchronizeTimeoutEvent:=RtlEventCreate;
  2321. InterlockedIncrement(ThreadQueueLockCounter);
  2322. InitCriticalSection(ThreadQueueLock);
  2323. MainThreadID:=GetCurrentThreadID;
  2324. {$else}
  2325. MainThreadID:=0{GetCurrentThreadID};
  2326. {$endif}
  2327. ExternalThreads := TThreadList.Create;
  2328. {$ifdef FPC_HAS_FEATURE_THREADING}
  2329. InitCriticalsection(ResolveSection);
  2330. TThread.FProcessorCount := CPUCount;
  2331. {$else}
  2332. TThread.FProcessorCount := 1{CPUCount};
  2333. {$endif}
  2334. InitHandlerList:=Nil;
  2335. FindGlobalComponentList:=nil;
  2336. IntConstList := TThreadList.Create;
  2337. ClassList := TThreadList.Create;
  2338. ClassAliasList := nil;
  2339. { on unix this maps to a simple rw synchornizer }
  2340. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  2341. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  2342. end;
  2343. procedure CommonCleanup;
  2344. var
  2345. i: Integer;
  2346. tmpentry: TThread.PThreadQueueEntry;
  2347. begin
  2348. {$ifdef FPC_HAS_FEATURE_THREADING}
  2349. GlobalNameSpace.BeginWrite;
  2350. {$endif}
  2351. with IntConstList.LockList do
  2352. try
  2353. for i := 0 to Count - 1 do
  2354. TIntConst(Items[I]).Free;
  2355. finally
  2356. IntConstList.UnlockList;
  2357. end;
  2358. IntConstList.Free;
  2359. ClassList.Free;
  2360. ClassAliasList.Free;
  2361. RemoveFixupReferences(nil, '');
  2362. {$ifdef FPC_HAS_FEATURE_THREADING}
  2363. DoneCriticalsection(ResolveSection);
  2364. {$endif}
  2365. GlobalLists.Free;
  2366. ComponentPages.Free;
  2367. FreeAndNil(NeedResolving);
  2368. {$ifdef FPC_HAS_FEATURE_THREADING}
  2369. GlobalNameSpace.EndWrite;
  2370. {$endif}
  2371. { GlobalNameSpace is an interface so this is enough }
  2372. GlobalNameSpace:=nil;
  2373. if (InitHandlerList<>Nil) then
  2374. for i := 0 to InitHandlerList.Count - 1 do
  2375. TInitHandler(InitHandlerList.Items[I]).Free;
  2376. InitHandlerList.Free;
  2377. InitHandlerList:=Nil;
  2378. FindGlobalComponentList.Free;
  2379. FindGlobalComponentList:=nil;
  2380. ExternalThreadsCleanup:=True;
  2381. with ExternalThreads.LockList do
  2382. try
  2383. for i := 0 to Count - 1 do
  2384. TThread(Items[i]).Free;
  2385. finally
  2386. ExternalThreads.UnlockList;
  2387. end;
  2388. FreeAndNil(ExternalThreads);
  2389. {$ifdef FPC_HAS_FEATURE_THREADING}
  2390. RtlEventDestroy(SynchronizeTimeoutEvent);
  2391. try
  2392. System.EnterCriticalSection(ThreadQueueLock);
  2393. {$endif}
  2394. { clean up the queue, but keep in mind that the entries used for Synchronize
  2395. are owned by the corresponding TThread }
  2396. while Assigned(ThreadQueueHead) do begin
  2397. tmpentry := ThreadQueueHead;
  2398. ThreadQueueHead := tmpentry^.Next;
  2399. if not Assigned(tmpentry^.SyncEvent) then
  2400. Dispose(tmpentry);
  2401. end;
  2402. { We also need to reset ThreadQueueTail }
  2403. ThreadQueueTail := nil;
  2404. {$ifdef FPC_HAS_FEATURE_THREADING}
  2405. finally
  2406. System.LeaveCriticalSection(ThreadQueueLock);
  2407. end;
  2408. if InterlockedDecrement(ThreadQueueLockCounter)=0 then
  2409. DoneCriticalSection(ThreadQueueLock);
  2410. {$endif}
  2411. end;
  2412. { TFiler implementation }
  2413. {$i filer.inc}
  2414. { TReader implementation }
  2415. {$i reader.inc}
  2416. { TWriter implementations }
  2417. {$i writer.inc}
  2418. {$i twriter.inc}