classes.inc 69 KB

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