classes.inc 54 KB

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