classes.inc 62 KB

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