classes.inc 54 KB

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