classes.inc 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786
  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. if Result then
  1230. Instance.ReadDeltaState;
  1231. {$ifdef FPC_HAS_FEATURE_THREADING}
  1232. finally
  1233. GlobalNameSpace.EndWrite;
  1234. end;
  1235. {$endif}
  1236. end;
  1237. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  1238. Var
  1239. I : Integer;
  1240. begin
  1241. I:=0;
  1242. if not Assigned(InitHandlerList) then begin
  1243. Result := True;
  1244. Exit;
  1245. end;
  1246. Result:=False;
  1247. With InitHandlerList do
  1248. begin
  1249. I:=0;
  1250. // Instance is the normally the lowest one, so that one should be used when searching.
  1251. While Not result and (I<Count) do
  1252. begin
  1253. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  1254. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  1255. Inc(I);
  1256. end;
  1257. end;
  1258. end;
  1259. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  1260. begin
  1261. Result:=ReadComponentRes(ResName,Instance)=Instance;
  1262. end;
  1263. function SysReadComponentRes(HInstance : THandle; const ResName: String; Instance: TComponent): TComponent;
  1264. Var
  1265. H : TFPResourceHandle;
  1266. begin
  1267. { Windows unit also has a FindResource function, use the one from
  1268. system unit here. }
  1269. H:=system.FindResource(HInstance,ResName,RT_RCDATA);
  1270. if (PtrInt(H)=0) then
  1271. Result:=Nil
  1272. else
  1273. With TResourceStream.Create(HInstance,ResName,RT_RCDATA) do
  1274. try
  1275. Result:=ReadComponent(Instance);
  1276. Finally
  1277. Free;
  1278. end;
  1279. end;
  1280. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  1281. begin
  1282. Result:=SysReadComponentRes(Hinstance,Resname,Instance);
  1283. end;
  1284. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  1285. begin
  1286. Result:=SysReadComponentRes(Hinstance,ResName,Nil);
  1287. end;
  1288. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  1289. var
  1290. FileStream: TStream;
  1291. begin
  1292. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  1293. try
  1294. Result := FileStream.ReadComponentRes(Instance);
  1295. finally
  1296. FileStream.Free;
  1297. end;
  1298. end;
  1299. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  1300. var
  1301. FileStream: TStream;
  1302. begin
  1303. FileStream := TFileStream.Create(FileName, fmCreate);
  1304. try
  1305. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  1306. finally
  1307. FileStream.Free;
  1308. end;
  1309. end;
  1310. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  1311. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  1312. Var
  1313. P : Integer;
  1314. CM : Boolean;
  1315. begin
  1316. P:=Pos('.',APath);
  1317. CM:=False;
  1318. If (P=0) then
  1319. begin
  1320. If CStyle then
  1321. begin
  1322. P:=Pos('->',APath);
  1323. CM:=P<>0;
  1324. end;
  1325. If (P=0) Then
  1326. P:=Length(APath)+1;
  1327. end;
  1328. Result:=Copy(APath,1,P-1);
  1329. Delete(APath,1,P+Ord(CM));
  1330. end;
  1331. Var
  1332. C : TComponent;
  1333. S : String;
  1334. begin
  1335. If (APath='') then
  1336. Result:=Nil
  1337. else
  1338. begin
  1339. Result:=Root;
  1340. While (APath<>'') And (Result<>Nil) do
  1341. begin
  1342. C:=Result;
  1343. S:=Uppercase(GetNextName);
  1344. Result:=C.FindComponent(S);
  1345. If (Result=Nil) And (S='OWNER') then
  1346. Result:=C;
  1347. end;
  1348. end;
  1349. end;
  1350. {$ifdef FPC_HAS_FEATURE_THREADING}
  1351. threadvar
  1352. {$else}
  1353. var
  1354. {$endif}
  1355. GlobalLoaded, GlobalLists: TFpList;
  1356. procedure BeginGlobalLoading;
  1357. begin
  1358. if not Assigned(GlobalLists) then
  1359. GlobalLists := TFpList.Create;
  1360. GlobalLists.Add(GlobalLoaded);
  1361. GlobalLoaded := TFpList.Create;
  1362. end;
  1363. { Notify all global components that they have been loaded completely }
  1364. procedure NotifyGlobalLoading;
  1365. var
  1366. i: Integer;
  1367. begin
  1368. for i := 0 to GlobalLoaded.Count - 1 do
  1369. TComponent(GlobalLoaded[i]).Loaded;
  1370. end;
  1371. procedure EndGlobalLoading;
  1372. begin
  1373. { Free the memory occupied by BeginGlobalLoading }
  1374. GlobalLoaded.Free;
  1375. GlobalLoaded := TFpList(GlobalLists.Last);
  1376. GlobalLists.Delete(GlobalLists.Count - 1);
  1377. if GlobalLists.Count = 0 then
  1378. begin
  1379. GlobalLists.Free;
  1380. GlobalLists := nil;
  1381. end;
  1382. end;
  1383. function CollectionsEqual(C1, C2: TCollection): Boolean;
  1384. begin
  1385. // !!!: Implement this
  1386. CollectionsEqual:=false;
  1387. end;
  1388. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  1389. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  1390. var
  1391. w : twriter;
  1392. begin
  1393. w:=twriter.create(s,4096);
  1394. try
  1395. w.root:=o;
  1396. w.flookuproot:=o;
  1397. w.writecollection(c);
  1398. finally
  1399. w.free;
  1400. end;
  1401. end;
  1402. var
  1403. s1,s2 : tmemorystream;
  1404. begin
  1405. result:=false;
  1406. if (c1.classtype<>c2.classtype) or
  1407. (c1.count<>c2.count) then
  1408. exit;
  1409. if c1.count = 0 then
  1410. begin
  1411. result:= true;
  1412. exit;
  1413. end;
  1414. s1:=tmemorystream.create;
  1415. try
  1416. s2:=tmemorystream.create;
  1417. try
  1418. stream_collection(s1,c1,owner1);
  1419. stream_collection(s2,c2,owner2);
  1420. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  1421. finally
  1422. s2.free;
  1423. end;
  1424. finally
  1425. s1.free;
  1426. end;
  1427. end;
  1428. { Object conversion routines }
  1429. type
  1430. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  1431. function CharToOrd(var P: Pointer): Cardinal;
  1432. begin
  1433. result:= ord(PAnsiChar(P)^);
  1434. inc(PAnsiChar(P));
  1435. end;
  1436. function WideCharToOrd(var P: Pointer): Cardinal;
  1437. begin
  1438. result:= ord(pwidechar(P)^);
  1439. inc(pwidechar(P));
  1440. end;
  1441. function Utf8ToOrd(var P:Pointer): Cardinal;
  1442. begin
  1443. // Should also check for illegal utf8 combinations
  1444. Result := Ord(PAnsiChar(P)^);
  1445. Inc(P);
  1446. if (Result and $80) <> 0 then
  1447. if (Ord(Result) and %11100000) = %11000000 then begin
  1448. Result := ((Result and %00011111) shl 6)
  1449. or (ord(PAnsiChar(P)^) and %00111111);
  1450. Inc(P);
  1451. end else if (Ord(Result) and %11110000) = %11100000 then begin
  1452. Result := ((Result and %00011111) shl 12)
  1453. or ((ord(PAnsiChar(P)^) and %00111111) shl 6)
  1454. or (ord((PAnsiChar(P)+1)^) and %00111111);
  1455. Inc(P,2);
  1456. end else begin
  1457. Result := ((ord(Result) and %00011111) shl 18)
  1458. or ((ord(PAnsiChar(P)^) and %00111111) shl 12)
  1459. or ((ord((PAnsiChar(P)+1)^) and %00111111) shl 6)
  1460. or (ord((PAnsiChar(P)+2)^) and %00111111);
  1461. Inc(P,3);
  1462. end;
  1463. end;
  1464. procedure ObjectBinaryToText(Input, Output: TStream; Encoding: TObjectTextEncoding);
  1465. var
  1466. Version: TBinaryObjectReader.TBOVersion;
  1467. procedure OutStr(s: RawByteString);
  1468. begin
  1469. if Length(s) > 0 then
  1470. Output.Write(s[1], Length(s));
  1471. end;
  1472. procedure OutLn(s: RawByteString);
  1473. begin
  1474. OutStr(s + LineEnding);
  1475. end;
  1476. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty;
  1477. UseBytes: boolean = false);
  1478. var
  1479. res, NewStr: RawByteString;
  1480. w: Cardinal;
  1481. InString, NewInString: Boolean;
  1482. begin
  1483. if p = nil then begin
  1484. res:= '''''';
  1485. end
  1486. else
  1487. begin
  1488. res := '';
  1489. InString := False;
  1490. while P < LastP do
  1491. begin
  1492. NewInString := InString;
  1493. w := CharToOrdfunc(P);
  1494. if w = ord('''') then
  1495. begin //quote AnsiChar
  1496. if not InString then
  1497. NewInString := True;
  1498. NewStr := '''''';
  1499. end
  1500. else if (Ord(w) >= 32) and ((Ord(w) < 127) or (UseBytes and (Ord(w)<256))) then
  1501. begin //printable ascii or bytes
  1502. if not InString then
  1503. NewInString := True;
  1504. NewStr := AnsiChar(w);
  1505. end
  1506. else
  1507. begin //ascii control chars, non ascii
  1508. if InString then
  1509. NewInString := False;
  1510. NewStr := '#' + IntToStr(w);
  1511. end;
  1512. if NewInString <> InString then
  1513. begin
  1514. NewStr := '''' + NewStr;
  1515. InString := NewInString;
  1516. end;
  1517. res := res + NewStr;
  1518. end;
  1519. if InString then
  1520. res := res + '''';
  1521. end;
  1522. OutStr(res);
  1523. end;
  1524. procedure OutString(s: RawByteString);
  1525. begin
  1526. OutChars(Pointer(S),PAnsiChar(S)+Length(S),@CharToOrd,Encoding=oteLFM);
  1527. end;
  1528. procedure OutWString(W: WideString);
  1529. begin
  1530. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1531. end;
  1532. procedure OutUString(W: UnicodeString);
  1533. begin
  1534. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  1535. end;
  1536. procedure OutUtf8Str(s: RawByteString);
  1537. begin
  1538. if Encoding=oteLFM then
  1539. OutChars(Pointer(S),PAnsiChar(S)+Length(S),@CharToOrd)
  1540. else
  1541. OutChars(Pointer(S),PAnsiChar(S)+Length(S),@Utf8ToOrd);
  1542. end;
  1543. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1544. begin
  1545. Result:=Input.ReadWord;
  1546. Result:=LEtoN(Result);
  1547. end;
  1548. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1549. begin
  1550. Result:=Input.ReadDWord;
  1551. Result:=LEtoN(Result);
  1552. end;
  1553. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1554. begin
  1555. Input.ReadBuffer(Result,sizeof(Result));
  1556. Result:=LEtoN(Result);
  1557. end;
  1558. {$ifndef FPUNONE}
  1559. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1560. function ExtendedToDouble(e : pointer) : double;
  1561. var mant : qword;
  1562. exp : smallint;
  1563. sign : boolean;
  1564. d : qword;
  1565. begin
  1566. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  1567. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  1568. mant:=LEtoN(mant);
  1569. exp:=LetoN(word(exp));
  1570. sign:=(exp and $8000)<>0;
  1571. if sign then exp:=exp and $7FFF;
  1572. case exp of
  1573. 0 : mant:=0; //if denormalized, value is too small for double,
  1574. //so it's always zero
  1575. $7FFF : exp:=2047 //either infinity or NaN
  1576. else
  1577. begin
  1578. dec(exp,16383-1023);
  1579. if (exp>=-51) and (exp<=0) then //can be denormalized
  1580. begin
  1581. mant:=mant shr (-exp);
  1582. exp:=0;
  1583. end
  1584. else
  1585. if (exp<-51) or (exp>2046) then //exponent too large.
  1586. begin
  1587. Result:=0;
  1588. exit;
  1589. end
  1590. else //normalized value
  1591. mant:=mant shl 1; //hide most significant bit
  1592. end;
  1593. end;
  1594. d:=word(exp);
  1595. d:=d shl 52;
  1596. mant:=mant shr 12;
  1597. d:=d or mant;
  1598. if sign then d:=d or $8000000000000000;
  1599. Result:=pdouble(@d)^;
  1600. end;
  1601. {$ENDIF}
  1602. {$endif}
  1603. function ReadInt(ValueType: TValueType): Int64;
  1604. begin
  1605. case ValueType of
  1606. vaInt8: Result := ShortInt(Input.ReadByte);
  1607. vaInt16: Result := SmallInt(ReadWord);
  1608. vaInt32: Result := LongInt(ReadDWord);
  1609. vaInt64: Result := Int64(ReadQWord);
  1610. end;
  1611. end;
  1612. function ReadInt: Int64;
  1613. begin
  1614. Result := ReadInt(TValueType(Input.ReadByte));
  1615. end;
  1616. {$ifndef FPUNONE}
  1617. function ReadExtended : extended;
  1618. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1619. var ext : array[0..9] of byte;
  1620. {$ENDIF}
  1621. begin
  1622. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1623. Input.ReadBuffer(ext[0],10);
  1624. Result:=ExtendedToDouble(@(ext[0]));
  1625. {$ELSE}
  1626. Input.ReadBuffer(Result,sizeof(Result));
  1627. {$ENDIF}
  1628. end;
  1629. {$endif}
  1630. function ReadSStr: RawByteString;
  1631. var
  1632. len: Byte;
  1633. begin
  1634. len := Input.ReadByte;
  1635. SetLength(Result, len);
  1636. if (len > 0) then
  1637. Input.ReadBuffer(Result[1], len);
  1638. end;
  1639. function ReadLStr: RawByteString;
  1640. var
  1641. len: DWord;
  1642. begin
  1643. len := ReadDWord;
  1644. SetLength(Result, len);
  1645. if (len > 0) then
  1646. Input.ReadBuffer(Result[1], len);
  1647. end;
  1648. function ReadWStr: WideString;
  1649. var
  1650. len: DWord;
  1651. {$IFDEF ENDIAN_BIG}
  1652. i : integer;
  1653. {$ENDIF}
  1654. begin
  1655. len := ReadDWord;
  1656. SetLength(Result, len);
  1657. if (len > 0) then
  1658. begin
  1659. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1660. {$IFDEF ENDIAN_BIG}
  1661. for i:=1 to len do
  1662. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1663. {$ENDIF}
  1664. end;
  1665. end;
  1666. function ReadUStr: UnicodeString;
  1667. var
  1668. len: DWord;
  1669. {$IFDEF ENDIAN_BIG}
  1670. i : integer;
  1671. {$ENDIF}
  1672. begin
  1673. len := ReadDWord;
  1674. SetLength(Result, len);
  1675. if (len > 0) then
  1676. begin
  1677. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  1678. {$IFDEF ENDIAN_BIG}
  1679. for i:=1 to len do
  1680. Result[i]:=widechar(SwapEndian(word(Result[i])));
  1681. {$ENDIF}
  1682. end;
  1683. end;
  1684. procedure ReadPropList(indent: RawByteString);
  1685. procedure ProcessValue(ValueType: TValueType; Indent: RawByteString);
  1686. procedure ProcessBinary;
  1687. var
  1688. ToDo, DoNow, i: LongInt;
  1689. lbuf: array[0..31] of Byte;
  1690. s: RawByteString;
  1691. begin
  1692. ToDo := ReadDWord;
  1693. OutLn('{');
  1694. while ToDo > 0 do begin
  1695. DoNow := ToDo;
  1696. if DoNow > 32 then DoNow := 32;
  1697. Dec(ToDo, DoNow);
  1698. s := Indent + ' ';
  1699. Input.ReadBuffer(lbuf, DoNow);
  1700. for i := 0 to DoNow - 1 do
  1701. s := s + IntToHex(lbuf[i], 2);
  1702. OutLn(s);
  1703. end;
  1704. OutLn(indent + '}');
  1705. end;
  1706. var
  1707. s: RawByteString;
  1708. { len: LongInt; }
  1709. IsFirst: Boolean;
  1710. {$ifndef FPUNONE}
  1711. ext: Extended;
  1712. {$endif}
  1713. begin
  1714. case ValueType of
  1715. vaList: begin
  1716. OutStr('(');
  1717. IsFirst := True;
  1718. while True do begin
  1719. ValueType := TValueType(Input.ReadByte);
  1720. if ValueType = vaNull then break;
  1721. if IsFirst then begin
  1722. OutLn('');
  1723. IsFirst := False;
  1724. end;
  1725. OutStr(Indent + ' ');
  1726. ProcessValue(ValueType, Indent + ' ');
  1727. end;
  1728. OutLn(Indent + ')');
  1729. end;
  1730. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  1731. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  1732. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  1733. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  1734. {$ifndef FPUNONE}
  1735. vaExtended: begin
  1736. ext:=ReadExtended;
  1737. Str(ext,S);// Do not use localized strings.
  1738. OutLn(S);
  1739. end;
  1740. {$endif}
  1741. vaString: begin
  1742. OutString(ReadSStr);
  1743. OutLn('');
  1744. end;
  1745. vaIdent: OutLn(ReadSStr);
  1746. vaFalse: OutLn('False');
  1747. vaTrue: OutLn('True');
  1748. vaBinary: ProcessBinary;
  1749. vaSet: begin
  1750. OutStr('[');
  1751. IsFirst := True;
  1752. while True do begin
  1753. s := ReadSStr;
  1754. if Length(s) = 0 then break;
  1755. if not IsFirst then OutStr(', ');
  1756. IsFirst := False;
  1757. OutStr(s);
  1758. end;
  1759. OutLn(']');
  1760. end;
  1761. vaLString:
  1762. begin
  1763. OutString(ReadLStr);
  1764. OutLn('');
  1765. end;
  1766. vaWString:
  1767. begin
  1768. OutWString(ReadWStr);
  1769. OutLn('');
  1770. end;
  1771. vaUString:
  1772. begin
  1773. OutWString(ReadWStr);
  1774. OutLn('');
  1775. end;
  1776. vaNil:
  1777. OutLn('nil');
  1778. vaCollection: begin
  1779. OutStr('<');
  1780. while Input.ReadByte <> 0 do begin
  1781. OutLn(Indent);
  1782. Input.Seek(-1, soFromCurrent);
  1783. OutStr(indent + ' item');
  1784. ValueType := TValueType(Input.ReadByte);
  1785. if ValueType <> vaList then
  1786. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1787. OutLn('');
  1788. ReadPropList(indent + ' ');
  1789. OutStr(indent + ' end');
  1790. end;
  1791. OutLn('>');
  1792. end;
  1793. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1794. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1795. vaDate: begin OutLn('!!Date!!'); exit end;}
  1796. vaUTF8String: begin
  1797. OutUtf8Str(ReadLStr);
  1798. OutLn('');
  1799. end;
  1800. else
  1801. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1802. end;
  1803. end;
  1804. begin
  1805. while Input.ReadByte <> 0 do begin
  1806. Input.Seek(-1, soFromCurrent);
  1807. OutStr(indent + ReadSStr + ' = ');
  1808. ProcessValue(TValueType(Input.ReadByte), Indent);
  1809. end;
  1810. end;
  1811. procedure ReadObject(indent: RawByteString);
  1812. var
  1813. b: Byte;
  1814. ObjUnitName, ObjClassName, ObjName: RawByteString;
  1815. ChildPos: LongInt;
  1816. ValueType: TValueType;
  1817. p: SizeInt;
  1818. begin
  1819. // Check for FilerFlags
  1820. b := Input.ReadByte;
  1821. if (b and $f0) = $f0 then begin
  1822. if (b and 2) <> 0 then ChildPos := ReadInt;
  1823. end else begin
  1824. b := 0;
  1825. Input.Seek(-1, soFromCurrent);
  1826. end;
  1827. ObjUnitName:='';
  1828. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  1829. begin
  1830. ValueType := TValueType(Input.ReadByte);
  1831. if ValueType=vaString then
  1832. ObjClassName := ReadSStr
  1833. else
  1834. ObjClassName := ReadLStr;
  1835. p:=Pos(TBinaryObjectReader.UnitnameSeparator,ObjClassName);
  1836. if p>0 then
  1837. begin
  1838. ObjUnitName:=copy(ObjClassName,1,p-1);
  1839. System.Delete(ObjClassName,1,p);
  1840. end;
  1841. end else
  1842. ObjClassName := ReadSStr;
  1843. ObjName := ReadSStr;
  1844. OutStr(Indent);
  1845. if (b and 1) <> 0 then
  1846. OutStr('inherited')
  1847. else if (b and 4) <> 0 then
  1848. OutStr('inline')
  1849. else
  1850. OutStr('object');
  1851. OutStr(' ');
  1852. if ObjName <> '' then
  1853. OutStr(ObjName + ': ');
  1854. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  1855. begin
  1856. OutStr(ObjUnitName);
  1857. OutStr('/');
  1858. end;
  1859. OutStr(ObjClassName);
  1860. if (b and 2) <> 0 then
  1861. OutStr('[' + IntToStr(ChildPos) + ']');
  1862. OutLn('');
  1863. ReadPropList(indent + ' ');
  1864. while Input.ReadByte <> 0 do begin
  1865. Input.Seek(-1, soFromCurrent);
  1866. ReadObject(indent + ' ');
  1867. end;
  1868. OutLn(indent + 'end');
  1869. end;
  1870. var
  1871. Signature: DWord;
  1872. begin
  1873. Signature:=Input.ReadDWord;
  1874. if Signature = DWord(unaligned(FilerSignature1)) then
  1875. Version:=TBinaryObjectReader.TBOVersion.boVersion1
  1876. else if Signature = DWord(unaligned(FilerSignature)) then
  1877. Version:=TBinaryObjectReader.TBOVersion.boVersion0
  1878. else
  1879. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1880. ReadObject('');
  1881. end;
  1882. procedure ObjectBinaryToText(Input, Output: TStream);
  1883. begin
  1884. ObjectBinaryToText(Input,Output,oteDFM);
  1885. end;
  1886. procedure ObjectTextToBinary(Input, Output: TStream);
  1887. var
  1888. parser: TParser;
  1889. Version: TBinaryObjectReader.TBOVersion;
  1890. StartPos: Int64;
  1891. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1892. begin
  1893. w:=NtoLE(w);
  1894. Output.WriteWord(w);
  1895. end;
  1896. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1897. begin
  1898. lw:=NtoLE(lw);
  1899. Output.WriteDWord(lw);
  1900. end;
  1901. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1902. begin
  1903. qw:=NtoLE(qw);
  1904. Output.WriteBuffer(qw,sizeof(qword));
  1905. end;
  1906. {$ifndef FPUNONE}
  1907. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1908. procedure DoubleToExtended(d : double; e : pointer);
  1909. var mant : qword;
  1910. exp : smallint;
  1911. sign : boolean;
  1912. begin
  1913. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1914. exp :=(qword(d) shr 52) and $7FF;
  1915. sign:=(qword(d) and $8000000000000000)<>0;
  1916. case exp of
  1917. 0 : begin
  1918. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1919. begin
  1920. exp:=16383-1022;
  1921. while (mant and $8000000000000000)=0 do
  1922. begin
  1923. dec(exp);
  1924. mant:=mant shl 1;
  1925. end;
  1926. dec(exp); //don't shift, most significant bit is not hidden in extended
  1927. end;
  1928. end;
  1929. 2047 : exp:=$7FFF //either infinity or NaN
  1930. else
  1931. begin
  1932. inc(exp,16383-1023);
  1933. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1934. end;
  1935. end;
  1936. if sign then exp:=exp or $8000;
  1937. mant:=NtoLE(mant);
  1938. exp:=NtoLE(word(exp));
  1939. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1940. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1941. end;
  1942. {$ENDIF}
  1943. procedure WriteExtended(const e : extended);
  1944. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1945. var ext : array[0..9] of byte;
  1946. {$ENDIF}
  1947. begin
  1948. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1949. DoubleToExtended(e,@(ext[0]));
  1950. Output.WriteBuffer(ext[0],10);
  1951. {$ELSE}
  1952. Output.WriteBuffer(e,sizeof(e));
  1953. {$ENDIF}
  1954. end;
  1955. {$endif}
  1956. procedure WriteSString(const s: RawByteString);
  1957. var size : byte;
  1958. begin
  1959. if length(s)>255 then size:=255
  1960. else size:=length(s);
  1961. Output.WriteByte(size);
  1962. if Length(s) > 0 then
  1963. Output.WriteBuffer(s[1], size);
  1964. end;
  1965. procedure WriteLString(Const s: RawByteString);
  1966. begin
  1967. WriteDWord(Length(s));
  1968. if Length(s) > 0 then
  1969. Output.WriteBuffer(s[1], Length(s));
  1970. end;
  1971. procedure WriteSorLString(Const s: String);
  1972. begin
  1973. if length(s)<256 then
  1974. begin
  1975. Output.WriteByte(Ord(vaString));
  1976. WriteSString(s);
  1977. end else begin
  1978. Output.WriteByte(Ord(vaLString));
  1979. WriteSString(s);
  1980. end;
  1981. end;
  1982. procedure WriteWString(Const s: WideString);
  1983. var len : longword;
  1984. {$IFDEF ENDIAN_BIG}
  1985. i : integer;
  1986. ws : widestring;
  1987. {$ENDIF}
  1988. begin
  1989. len:=Length(s);
  1990. WriteDWord(len);
  1991. if len > 0 then
  1992. begin
  1993. {$IFDEF ENDIAN_BIG}
  1994. setlength(ws,len);
  1995. for i:=1 to len do
  1996. ws[i]:=widechar(SwapEndian(word(s[i])));
  1997. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1998. {$ELSE}
  1999. Output.WriteBuffer(s[1], len*sizeof(widechar));
  2000. {$ENDIF}
  2001. end;
  2002. end;
  2003. procedure WriteInteger(value: Int64);
  2004. begin
  2005. if (value >= -128) and (value <= 127) then begin
  2006. Output.WriteByte(Ord(vaInt8));
  2007. Output.WriteByte(byte(value));
  2008. end else if (value >= -32768) and (value <= 32767) then begin
  2009. Output.WriteByte(Ord(vaInt16));
  2010. WriteWord(word(value));
  2011. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  2012. Output.WriteByte(Ord(vaInt32));
  2013. WriteDWord(longword(value));
  2014. end else begin
  2015. Output.WriteByte(ord(vaInt64));
  2016. WriteQWord(qword(value));
  2017. end;
  2018. end;
  2019. procedure ProcessWideString(const left : widestring);
  2020. var ws : widestring;
  2021. begin
  2022. ws:=left+parser.TokenWideString;
  2023. while parser.NextToken = '+' do
  2024. begin
  2025. parser.NextToken; // Get next string fragment
  2026. if not (parser.Token in [toString,toWString]) then
  2027. parser.CheckToken(toWString);
  2028. ws:=ws+parser.TokenWideString;
  2029. end;
  2030. Output.WriteByte(Ord(vaWstring));
  2031. WriteWString(ws);
  2032. end;
  2033. procedure ProcessProperty; forward;
  2034. procedure ProcessValue;
  2035. var
  2036. {$ifndef FPUNONE}
  2037. flt: Extended;
  2038. {$endif}
  2039. s: RawByteString;
  2040. stream: TMemoryStream;
  2041. begin
  2042. case parser.Token of
  2043. toInteger:
  2044. begin
  2045. WriteInteger(parser.TokenInt);
  2046. parser.NextToken;
  2047. end;
  2048. {$ifndef FPUNONE}
  2049. toFloat:
  2050. begin
  2051. Output.WriteByte(Ord(vaExtended));
  2052. flt := Parser.TokenFloat;
  2053. WriteExtended(flt);
  2054. parser.NextToken;
  2055. end;
  2056. {$endif}
  2057. toString:
  2058. begin
  2059. s := parser.TokenString;
  2060. while parser.NextToken = '+' do
  2061. begin
  2062. parser.NextToken; // Get next string fragment
  2063. case parser.Token of
  2064. toString : s:=s+parser.TokenString;
  2065. toWString : begin
  2066. ProcessWideString(WideString(s));
  2067. exit;
  2068. end
  2069. else parser.CheckToken(toString);
  2070. end;
  2071. end;
  2072. if (length(S)>255) then
  2073. begin
  2074. Output.WriteByte(Ord(vaLString));
  2075. WriteLString(S);
  2076. end
  2077. else
  2078. begin
  2079. Output.WriteByte(Ord(vaString));
  2080. WriteSString(s);
  2081. end;
  2082. end;
  2083. toWString:
  2084. ProcessWideString('');
  2085. toSymbol:
  2086. begin
  2087. if CompareText(parser.TokenString, 'True') = 0 then
  2088. Output.WriteByte(Ord(vaTrue))
  2089. else if CompareText(parser.TokenString, 'False') = 0 then
  2090. Output.WriteByte(Ord(vaFalse))
  2091. else if CompareText(parser.TokenString, 'nil') = 0 then
  2092. Output.WriteByte(Ord(vaNil))
  2093. else
  2094. begin
  2095. Output.WriteByte(Ord(vaIdent));
  2096. WriteSString(parser.TokenComponentIdent);
  2097. end;
  2098. Parser.NextToken;
  2099. end;
  2100. // Set
  2101. '[':
  2102. begin
  2103. parser.NextToken;
  2104. Output.WriteByte(Ord(vaSet));
  2105. if parser.Token <> ']' then
  2106. while True do
  2107. begin
  2108. parser.CheckToken(toSymbol);
  2109. WriteSString(parser.TokenString);
  2110. parser.NextToken;
  2111. if parser.Token = ']' then
  2112. break;
  2113. parser.CheckToken(',');
  2114. parser.NextToken;
  2115. end;
  2116. Output.WriteByte(0);
  2117. parser.NextToken;
  2118. end;
  2119. // List
  2120. '(':
  2121. begin
  2122. parser.NextToken;
  2123. Output.WriteByte(Ord(vaList));
  2124. while parser.Token <> ')' do
  2125. ProcessValue;
  2126. Output.WriteByte(0);
  2127. parser.NextToken;
  2128. end;
  2129. // Collection
  2130. '<':
  2131. begin
  2132. parser.NextToken;
  2133. Output.WriteByte(Ord(vaCollection));
  2134. while parser.Token <> '>' do
  2135. begin
  2136. parser.CheckTokenSymbol('item');
  2137. parser.NextToken;
  2138. // ConvertOrder
  2139. Output.WriteByte(Ord(vaList));
  2140. while not parser.TokenSymbolIs('end') do
  2141. ProcessProperty;
  2142. parser.NextToken; // Skip 'end'
  2143. Output.WriteByte(0);
  2144. end;
  2145. Output.WriteByte(0);
  2146. parser.NextToken;
  2147. end;
  2148. // Binary data
  2149. '{':
  2150. begin
  2151. Output.WriteByte(Ord(vaBinary));
  2152. stream := TMemoryStream.Create;
  2153. try
  2154. parser.HexToBinary(stream);
  2155. WriteDWord(stream.Size);
  2156. Output.WriteBuffer(Stream.Memory^, stream.Size);
  2157. finally
  2158. stream.Free;
  2159. end;
  2160. parser.NextToken;
  2161. end;
  2162. else
  2163. parser.Error(SInvalidProperty);
  2164. end;
  2165. end;
  2166. procedure ProcessProperty;
  2167. var
  2168. name: RawByteString;
  2169. begin
  2170. // Get name of property
  2171. parser.CheckToken(toSymbol);
  2172. name := parser.TokenString;
  2173. while True do begin
  2174. parser.NextToken;
  2175. if parser.Token <> '.' then break;
  2176. parser.NextToken;
  2177. parser.CheckToken(toSymbol);
  2178. name := name + '.' + parser.TokenString;
  2179. end;
  2180. WriteSString(name);
  2181. parser.CheckToken('=');
  2182. parser.NextToken;
  2183. ProcessValue;
  2184. end;
  2185. procedure ProcessObject(Root: boolean);
  2186. var
  2187. Flags: Byte;
  2188. ObjectName, ObjUnitName, ObjClassName: RawByteString;
  2189. ChildPos: Integer;
  2190. begin
  2191. if parser.TokenSymbolIs('OBJECT') then
  2192. Flags :=0 { IsInherited := False }
  2193. else begin
  2194. if parser.TokenSymbolIs('INHERITED') then
  2195. Flags := 1 { IsInherited := True; }
  2196. else begin
  2197. parser.CheckTokenSymbol('INLINE');
  2198. Flags := 4;
  2199. end;
  2200. end;
  2201. parser.NextToken;
  2202. parser.CheckToken(toSymbol);
  2203. ObjectName := '';
  2204. ObjUnitName := '';
  2205. ObjClassName := parser.TokenString;
  2206. parser.NextToken;
  2207. if parser.Token = '/' then begin
  2208. ObjUnitName := ObjClassName;
  2209. parser.NextToken;
  2210. parser.CheckToken(toSymbol);
  2211. ObjClassName := parser.TokenString;
  2212. parser.NextToken;
  2213. end else if parser.Token = ':' then begin
  2214. parser.NextToken;
  2215. parser.CheckToken(toSymbol);
  2216. ObjectName := ObjClassName;
  2217. ObjClassName := parser.TokenString;
  2218. parser.NextToken;
  2219. if parser.Token = '/' then begin
  2220. ObjUnitName := ObjClassName;
  2221. parser.NextToken;
  2222. parser.CheckToken(toSymbol);
  2223. ObjClassName := parser.TokenString;
  2224. parser.NextToken;
  2225. end;
  2226. if parser.Token = '[' then begin
  2227. parser.NextToken;
  2228. ChildPos := parser.TokenInt;
  2229. parser.NextToken;
  2230. parser.CheckToken(']');
  2231. parser.NextToken;
  2232. Flags := Flags or 2;
  2233. end;
  2234. end;
  2235. if Root then
  2236. begin
  2237. if (ObjUnitName<>'') then
  2238. Version:=TBinaryObjectReader.TBOVersion.boVersion1;
  2239. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  2240. Output.WriteBuffer(FilerSignature1[1], length(FilerSignature1))
  2241. else
  2242. Output.WriteBuffer(FilerSignature[1], length(FilerSignature));
  2243. end;
  2244. if Flags <> 0 then begin
  2245. Output.WriteByte($f0 or Flags);
  2246. if (Flags and 2) <> 0 then
  2247. WriteInteger(ChildPos);
  2248. end;
  2249. if Version=TBinaryObjectReader.TBOVersion.boVersion1 then
  2250. WriteSorLString(ObjUnitName+TBinaryObjectReader.UnitnameSeparator+ObjClassName)
  2251. else
  2252. WriteSString(ObjClassName);
  2253. WriteSString(ObjectName);
  2254. // Convert property list
  2255. while not (parser.TokenSymbolIs('END') or
  2256. parser.TokenSymbolIs('OBJECT') or
  2257. parser.TokenSymbolIs('INHERITED') or
  2258. parser.TokenSymbolIs('INLINE')) do
  2259. ProcessProperty;
  2260. Output.WriteByte(0); // Terminate property list
  2261. // Convert child objects
  2262. while not parser.TokenSymbolIs('END') do ProcessObject(false);
  2263. parser.NextToken; // Skip end token
  2264. Output.WriteByte(0); // Terminate property list
  2265. end;
  2266. const
  2267. signature: PAnsiChar = 'TPF0';
  2268. begin
  2269. Version:=TBinaryObjectReader.TBOVersion.boVersion0;
  2270. parser := TParser.Create(Input);
  2271. try
  2272. StartPos:=Output.Position;
  2273. ProcessObject(true);
  2274. finally
  2275. parser.Free;
  2276. end;
  2277. end;
  2278. procedure ObjectResourceToText(Input, Output: TStream);
  2279. begin
  2280. Input.ReadResHeader;
  2281. ObjectBinaryToText(Input, Output);
  2282. end;
  2283. procedure ObjectTextToResource(Input, Output: TStream);
  2284. var
  2285. StartPos, FixupInfo: LongInt;
  2286. parser: TParser;
  2287. name: String;
  2288. begin
  2289. // Get form type name
  2290. StartPos := Input.Position;
  2291. parser := TParser.Create(Input);
  2292. try
  2293. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  2294. parser.NextToken;
  2295. parser.CheckToken(toSymbol);
  2296. parser.NextToken;
  2297. parser.CheckToken(':');
  2298. parser.NextToken;
  2299. parser.CheckToken(toSymbol);
  2300. name := parser.TokenString;
  2301. finally
  2302. parser.Free;
  2303. Input.Position := StartPos;
  2304. end;
  2305. name := UpperCase(name);
  2306. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  2307. ObjectTextToBinary(Input, Output); // Convert the stuff!
  2308. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  2309. end;
  2310. { Utility routines }
  2311. Function IfThen(AValue: Boolean; const ATrue: TStringList; const AFalse: TStringList = nil): TStringList; overload;
  2312. begin
  2313. if avalue then
  2314. result:=atrue
  2315. else
  2316. result:=afalse;
  2317. end;
  2318. function LineStart(Buffer, BufPos: PAnsiChar): PAnsiChar;
  2319. begin
  2320. Result := BufPos;
  2321. while Result > Buffer do begin
  2322. Dec(Result);
  2323. if Result[0] = #10 then break;
  2324. end;
  2325. end;
  2326. procedure CommonInit;
  2327. begin
  2328. {$ifdef FPC_HAS_FEATURE_THREADING}
  2329. SynchronizeTimeoutEvent:=RtlEventCreate;
  2330. InterlockedIncrement(ThreadQueueLockCounter);
  2331. InitCriticalSection(ThreadQueueLock);
  2332. MainThreadID:=GetCurrentThreadID;
  2333. {$else}
  2334. MainThreadID:=0{GetCurrentThreadID};
  2335. {$endif}
  2336. ExternalThreads := TThreadList.Create;
  2337. {$ifdef FPC_HAS_FEATURE_THREADING}
  2338. InitCriticalsection(ResolveSection);
  2339. TThread.FProcessorCount := CPUCount;
  2340. {$else}
  2341. TThread.FProcessorCount := 1{CPUCount};
  2342. {$endif}
  2343. InitHandlerList:=Nil;
  2344. FindGlobalComponentList:=nil;
  2345. IntConstList := TThreadList.Create;
  2346. ClassList := TThreadList.Create;
  2347. ClassAliasList := nil;
  2348. { on unix this maps to a simple rw synchornizer }
  2349. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  2350. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  2351. end;
  2352. procedure CommonCleanup;
  2353. var
  2354. i: Integer;
  2355. tmpentry: TThread.PThreadQueueEntry;
  2356. begin
  2357. {$ifdef FPC_HAS_FEATURE_THREADING}
  2358. GlobalNameSpace.BeginWrite;
  2359. {$endif}
  2360. with IntConstList.LockList do
  2361. try
  2362. for i := 0 to Count - 1 do
  2363. TIntConst(Items[I]).Free;
  2364. finally
  2365. IntConstList.UnlockList;
  2366. end;
  2367. IntConstList.Free;
  2368. ClassList.Free;
  2369. ClassAliasList.Free;
  2370. RemoveFixupReferences(nil, '');
  2371. {$ifdef FPC_HAS_FEATURE_THREADING}
  2372. DoneCriticalsection(ResolveSection);
  2373. {$endif}
  2374. GlobalLists.Free;
  2375. ComponentPages.Free;
  2376. FreeAndNil(NeedResolving);
  2377. {$ifdef FPC_HAS_FEATURE_THREADING}
  2378. GlobalNameSpace.EndWrite;
  2379. {$endif}
  2380. { GlobalNameSpace is an interface so this is enough }
  2381. GlobalNameSpace:=nil;
  2382. if (InitHandlerList<>Nil) then
  2383. for i := 0 to InitHandlerList.Count - 1 do
  2384. TInitHandler(InitHandlerList.Items[I]).Free;
  2385. InitHandlerList.Free;
  2386. InitHandlerList:=Nil;
  2387. FindGlobalComponentList.Free;
  2388. FindGlobalComponentList:=nil;
  2389. ExternalThreadsCleanup:=True;
  2390. with ExternalThreads.LockList do
  2391. try
  2392. for i := 0 to Count - 1 do
  2393. TThread(Items[i]).Free;
  2394. finally
  2395. ExternalThreads.UnlockList;
  2396. end;
  2397. FreeAndNil(ExternalThreads);
  2398. {$ifdef FPC_HAS_FEATURE_THREADING}
  2399. RtlEventDestroy(SynchronizeTimeoutEvent);
  2400. try
  2401. System.EnterCriticalSection(ThreadQueueLock);
  2402. {$endif}
  2403. { clean up the queue, but keep in mind that the entries used for Synchronize
  2404. are owned by the corresponding TThread }
  2405. while Assigned(ThreadQueueHead) do begin
  2406. tmpentry := ThreadQueueHead;
  2407. ThreadQueueHead := tmpentry^.Next;
  2408. if not Assigned(tmpentry^.SyncEvent) then
  2409. Dispose(tmpentry);
  2410. end;
  2411. { We also need to reset ThreadQueueTail }
  2412. ThreadQueueTail := nil;
  2413. {$ifdef FPC_HAS_FEATURE_THREADING}
  2414. finally
  2415. System.LeaveCriticalSection(ThreadQueueLock);
  2416. end;
  2417. if InterlockedDecrement(ThreadQueueLockCounter)=0 then
  2418. DoneCriticalSection(ThreadQueueLock);
  2419. {$endif}
  2420. end;
  2421. { TFiler implementation }
  2422. {$i filer.inc}
  2423. { TReader implementation }
  2424. {$i reader.inc}
  2425. { TWriter implementations }
  2426. {$i writer.inc}
  2427. {$i twriter.inc}
  2428. constructor ComponentPlatformsAttribute.Create(const aPlatforms: TPlatformIds);
  2429. begin
  2430. FPlatForms:=aPlatForms;
  2431. end;