classes.inc 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736
  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. var
  14. ClassList : TThreadlist;
  15. ClassAliasList : TStringList;
  16. {
  17. Include all message strings
  18. Add a language with IFDEF LANG_NAME
  19. just befor the final ELSE. This way English will always be the default.
  20. }
  21. {$IFDEF LANG_GERMAN}
  22. {$i constsg.inc}
  23. {$ELSE}
  24. {$IFDEF LANG_SPANISH}
  25. {$i constss.inc}
  26. {$ENDIF}
  27. {$ENDIF}
  28. { Utility routines }
  29. {$i util.inc}
  30. { TBits implementation }
  31. {$i bits.inc}
  32. { All streams implementations: }
  33. { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
  34. { TCustomMemoryStream TMemoryStream }
  35. {$i streams.inc}
  36. { TParser implementation}
  37. {$i parser.inc}
  38. { TCollection and TCollectionItem implementations }
  39. {$i collect.inc}
  40. { TList and TThreadList implementations }
  41. {$i lists.inc}
  42. { TStrings and TStringList implementations }
  43. {$i stringl.inc}
  44. { TThread implementation }
  45. { system independend threading code }
  46. var
  47. { event that happens when gui thread is done executing the method}
  48. ExecuteEvent: PRtlEvent;
  49. { event executed by synchronize to wake main thread if it sleeps in CheckSynchronize }
  50. SynchronizeTimeoutEvent: PRtlEvent;
  51. { guard for synchronization variables }
  52. SynchronizeCritSect: TRtlCriticalSection;
  53. { method to execute }
  54. SynchronizeMethod: TThreadMethod;
  55. { should we execute the method? }
  56. DoSynchronizeMethod: boolean;
  57. { caught exception in gui thread, to be raised in calling thread }
  58. SynchronizeException: Exception;
  59. function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
  60. var
  61. FreeThread: Boolean;
  62. Thread: TThread absolute ThreadObjPtr;
  63. begin
  64. { if Suspend checks FSuspended before doing anything, make sure it }
  65. { knows we're currently not suspended (this flag may have been set }
  66. { to true if CreateSuspended was true) }
  67. // Thread.FSuspended:=false;
  68. // wait until AfterConstruction has been called, so we cannot
  69. // free ourselves before TThread.Create has finished
  70. // (since that one may check our VTM in case of $R+, and
  71. // will call the AfterConstruction method in all cases)
  72. // Thread.Suspend;
  73. try
  74. Thread.Execute;
  75. except
  76. Thread.FFatalException := TObject(AcquireExceptionObject);
  77. end;
  78. FreeThread := Thread.FFreeOnTerminate;
  79. Result := Thread.FReturnValue;
  80. Thread.FFinished := True;
  81. Thread.DoTerminate;
  82. if FreeThread then
  83. Thread.Free;
  84. EndThread(Result);
  85. end;
  86. { system-dependent code }
  87. {$i tthread.inc}
  88. function TThread.GetSuspended: Boolean;
  89. begin
  90. GetSuspended:=FSuspended;
  91. end;
  92. procedure TThread.AfterConstruction;
  93. begin
  94. inherited AfterConstruction;
  95. // Resume;
  96. end;
  97. class procedure TThread.Synchronize(AThread: TThread; AMethod: TThreadMethod);
  98. var
  99. LocalSyncException: Exception;
  100. begin
  101. { do we really need a synchronized call? }
  102. if GetCurrentThreadID=MainThreadID then
  103. AMethod()
  104. else
  105. begin
  106. System.EnterCriticalSection(SynchronizeCritSect);
  107. SynchronizeException:=nil;
  108. SynchronizeMethod:=AMethod;
  109. { be careful, after this assignment Method could be already executed }
  110. DoSynchronizeMethod:=true;
  111. RtlEventSetEvent(SynchronizeTimeoutEvent);
  112. if assigned(WakeMainThread) then
  113. WakeMainThread(AThread);
  114. { wait infinitely }
  115. RtlEventWaitFor(ExecuteEvent);
  116. LocalSyncException:=SynchronizeException;
  117. System.LeaveCriticalSection(SynchronizeCritSect);
  118. if assigned(LocalSyncException) then
  119. raise LocalSyncException;
  120. end;
  121. end;
  122. procedure TThread.Synchronize(AMethod: TThreadMethod);
  123. begin
  124. TThread.Synchronize(self,AMethod);
  125. end;
  126. function CheckSynchronize(timeout : longint=0) : boolean;
  127. { assumes being called from GUI thread }
  128. begin
  129. result:=false;
  130. { first sanity check }
  131. if Not IsMultiThread then
  132. Exit
  133. { second sanity check }
  134. else if GetCurrentThreadID<>MainThreadID then
  135. raise EThread.CreateFmt(SCheckSynchronizeError,[GetCurrentThreadID])
  136. else
  137. begin
  138. if timeout>0 then
  139. begin
  140. RtlEventWaitFor(SynchronizeTimeoutEvent,timeout);
  141. end
  142. else
  143. RtlEventResetEvent(SynchronizeTimeoutEvent);
  144. if DoSynchronizeMethod then
  145. begin
  146. DoSynchronizeMethod:=false;
  147. try
  148. SynchronizeMethod;
  149. result:=true;
  150. except
  151. SynchronizeException:=Exception(AcquireExceptionObject);
  152. end;
  153. RtlEventSetEvent(ExecuteEvent);
  154. end;
  155. end;
  156. end;
  157. { TPersistent implementation }
  158. {$i persist.inc }
  159. {$i sllist.inc}
  160. {$i resref.inc}
  161. { TComponent implementation }
  162. {$i compon.inc}
  163. { TBasicAction implementation }
  164. {$i action.inc}
  165. { TDataModule implementation }
  166. {$i dm.inc}
  167. { Class and component registration routines }
  168. {$I cregist.inc}
  169. { Interface related stuff }
  170. {$I intf.inc}
  171. {**********************************************************************
  172. * Miscellaneous procedures and functions *
  173. **********************************************************************}
  174. function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings): Integer;
  175. var
  176. b, c : pchar;
  177. procedure SkipWhitespace;
  178. begin
  179. while (c^ in Whitespace) do
  180. inc (c);
  181. end;
  182. procedure AddString;
  183. var
  184. l : integer;
  185. s : string;
  186. begin
  187. l := c-b;
  188. if l > 0 then
  189. begin
  190. if assigned(Strings) then
  191. begin
  192. setlength(s, l);
  193. move (b^, s[1],l);
  194. Strings.Add (s);
  195. end;
  196. inc (result);
  197. end;
  198. end;
  199. var
  200. quoted : char;
  201. begin
  202. result := 0;
  203. c := Content;
  204. Quoted := #0;
  205. Separators := Separators + [#13, #10] - ['''','"'];
  206. SkipWhitespace;
  207. b := c;
  208. while (c^ <> #0) do
  209. begin
  210. if (c^ = Quoted) then
  211. begin
  212. if ((c+1)^ = Quoted) then
  213. inc (c)
  214. else
  215. Quoted := #0
  216. end
  217. else if (Quoted = #0) and (c^ in ['''','"']) then
  218. Quoted := c^;
  219. if (Quoted = #0) and (c^ in Separators) then
  220. begin
  221. AddString;
  222. inc (c);
  223. SkipWhitespace;
  224. b := c;
  225. end
  226. else
  227. inc (c);
  228. end;
  229. if (c <> b) then
  230. AddString;
  231. end;
  232. { Point and rectangle constructors }
  233. function Point(AX, AY: Integer): TPoint;
  234. begin
  235. with Result do
  236. begin
  237. X := AX;
  238. Y := AY;
  239. end;
  240. end;
  241. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  242. begin
  243. with Result do
  244. begin
  245. X := AX;
  246. Y := AY;
  247. end;
  248. end;
  249. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  250. begin
  251. with Result do
  252. begin
  253. Left := ALeft;
  254. Top := ATop;
  255. Right := ARight;
  256. Bottom := ABottom;
  257. end;
  258. end;
  259. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  260. begin
  261. with Result do
  262. begin
  263. Left := ALeft;
  264. Top := ATop;
  265. Right := ALeft + AWidth;
  266. Bottom := ATop + AHeight;
  267. end;
  268. end;
  269. function PointsEqual(const P1, P2: TPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  270. begin
  271. { lazy, but should work }
  272. result:=QWord(P1)=QWord(P2);
  273. end;
  274. function PointsEqual(const P1, P2: TSmallPoint): Boolean; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  275. begin
  276. { lazy, but should work }
  277. result:=DWord(P1)=DWord(P2);
  278. end;
  279. function InvalidPoint(X, Y: Integer): Boolean;
  280. begin
  281. result:=(X=-1) and (Y=-1);
  282. end;
  283. function InvalidPoint(const At: TPoint): Boolean;
  284. begin
  285. result:=(At.x=-1) and (At.y=-1);
  286. end;
  287. function InvalidPoint(const At: TSmallPoint): Boolean;
  288. begin
  289. result:=(At.x=-1) and (At.y=-1);
  290. end;
  291. { Object filing routines }
  292. var
  293. IntConstList: TThreadList;
  294. type
  295. TIntConst = class
  296. IntegerType: PTypeInfo; // The integer type RTTI pointer
  297. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  298. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  299. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  300. AIntToIdent: TIntToIdent);
  301. end;
  302. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  303. AIntToIdent: TIntToIdent);
  304. begin
  305. IntegerType := AIntegerType;
  306. IdentToIntFn := AIdentToInt;
  307. IntToIdentFn := AIntToIdent;
  308. end;
  309. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  310. IntToIdentFn: TIntToIdent);
  311. begin
  312. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  313. end;
  314. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  315. var
  316. i: Integer;
  317. begin
  318. with IntConstList.LockList do
  319. try
  320. for i := 0 to Count - 1 do
  321. if TIntConst(Items[i]).IntegerType = AIntegerType then
  322. exit(TIntConst(Items[i]).IntToIdentFn);
  323. Result := nil;
  324. finally
  325. IntConstList.UnlockList;
  326. end;
  327. end;
  328. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  329. var
  330. i: Integer;
  331. begin
  332. with IntConstList.LockList do
  333. try
  334. for i := 0 to Count - 1 do
  335. with TIntConst(Items[I]) do
  336. if TIntConst(Items[I]).IntegerType = AIntegerType then
  337. exit(IdentToIntFn);
  338. Result := nil;
  339. finally
  340. IntConstList.UnlockList;
  341. end;
  342. end;
  343. function IdentToInt(const Ident: String; var Int: LongInt;
  344. const Map: array of TIdentMapEntry): Boolean;
  345. var
  346. i: Integer;
  347. begin
  348. for i := Low(Map) to High(Map) do
  349. if CompareText(Map[i].Name, Ident) = 0 then
  350. begin
  351. Int := Map[i].Value;
  352. exit(True);
  353. end;
  354. Result := False;
  355. end;
  356. function IntToIdent(Int: LongInt; var Ident: String;
  357. const Map: array of TIdentMapEntry): Boolean;
  358. var
  359. i: Integer;
  360. begin
  361. for i := Low(Map) to High(Map) do
  362. if Map[i].Value = Int then
  363. begin
  364. Ident := Map[i].Name;
  365. exit(True);
  366. end;
  367. Result := False;
  368. end;
  369. function GlobalIdentToInt(const Ident: String; var Int: LongInt):boolean;
  370. var
  371. i : Integer;
  372. begin
  373. with IntConstList.LockList do
  374. try
  375. for i := 0 to Count - 1 do
  376. if TIntConst(Items[I]).IdentToIntFn(Ident, Int) then
  377. Exit(True);
  378. Result := false;
  379. finally
  380. IntConstList.UnlockList;
  381. end;
  382. end;
  383. { TPropFixup }
  384. // Tainted. TPropFixup is being removed.
  385. Type
  386. TInitHandler = Class(TObject)
  387. AHandler : TInitComponentHandler;
  388. AClass : TComponentClass;
  389. end;
  390. Var
  391. InitHandlerList : TList;
  392. FindGlobalComponentList : TList;
  393. procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  394. begin
  395. if not(assigned(FindGlobalComponentList)) then
  396. FindGlobalComponentList:=TList.Create;
  397. if FindGlobalComponentList.IndexOf(Pointer(AFindGlobalComponent))<0 then
  398. FindGlobalComponentList.Add(Pointer(AFindGlobalComponent));
  399. end;
  400. procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
  401. begin
  402. if assigned(FindGlobalComponentList) then
  403. FindGlobalComponentList.Remove(Pointer(AFindGlobalComponent));
  404. end;
  405. function FindGlobalComponent(const Name: string): TComponent;
  406. var
  407. i : sizeint;
  408. begin
  409. FindGlobalComponent:=nil;
  410. if assigned(FindGlobalComponentList) then
  411. begin
  412. for i:=FindGlobalComponentList.Count-1 downto 0 do
  413. begin
  414. FindGlobalComponent:=TFindGlobalComponent(FindGlobalComponentList[i])(name);
  415. if assigned(FindGlobalComponent) then
  416. break;
  417. end;
  418. end;
  419. end;
  420. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  421. Var
  422. I : Integer;
  423. H: TInitHandler;
  424. begin
  425. If (InitHandlerList=Nil) then
  426. InitHandlerList:=TList.Create;
  427. H:=TInitHandler.Create;
  428. H.Aclass:=ComponentClass;
  429. H.AHandler:=Handler;
  430. try
  431. With InitHandlerList do
  432. begin
  433. I:=0;
  434. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[I]).AClass) do
  435. Inc(I);
  436. { override? }
  437. if (I<Count) and (TInitHandler(Items[I]).AClass=H.AClass) then
  438. begin
  439. TInitHandler(Items[I]).AHandler:=Handler;
  440. H.Free;
  441. end
  442. else
  443. InitHandlerList.Insert(I,H);
  444. end;
  445. except
  446. H.Free;
  447. raise;
  448. end;
  449. end;
  450. { all targets should at least include the sysres.inc dummy in the system unit to compile this }
  451. function CreateComponentfromRes(const res : string;Inst : THandle;var Component : TComponent) : Boolean;
  452. var
  453. ResStream : TResourceStream;
  454. begin
  455. result:=true;
  456. if Inst=0 then
  457. Inst:=HInstance;
  458. try
  459. ResStream:=TResourceStream.Create(Inst,res,RT_RCDATA);
  460. try
  461. Component:=ResStream.ReadComponent(Component);
  462. finally
  463. ResStream.Free;
  464. end;
  465. except
  466. on EResNotFound do
  467. result:=false;
  468. end;
  469. end;
  470. function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
  471. function doinit(_class : TClass) : boolean;
  472. begin
  473. result:=false;
  474. if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
  475. exit;
  476. result:=doinit(_class.ClassParent);
  477. result:=CreateComponentfromRes(_class.ClassName,0,Instance) or result;
  478. end;
  479. begin
  480. GlobalNameSpace.BeginWrite;
  481. try
  482. result:=doinit(Instance.ClassType);
  483. finally
  484. GlobalNameSpace.EndWrite;
  485. end;
  486. end;
  487. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  488. Var
  489. I : Integer;
  490. begin
  491. I:=0;
  492. if not Assigned(InitHandlerList) then begin
  493. Result := True;
  494. Exit;
  495. end;
  496. Result:=False;
  497. With InitHandlerList do
  498. begin
  499. I:=0;
  500. // Instance is the normally the lowest one, so that one should be used when searching.
  501. While Not result and (I<Count) do
  502. begin
  503. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  504. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  505. Inc(I);
  506. end;
  507. end;
  508. end;
  509. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  510. begin
  511. { !!!: Too Win32-specific }
  512. InitComponentRes := False;
  513. end;
  514. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  515. begin
  516. { !!!: Too Win32-specific }
  517. ReadComponentRes := nil;
  518. end;
  519. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  520. begin
  521. { !!!: Too Win32-specific in VCL }
  522. ReadComponentResEx := nil;
  523. end;
  524. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  525. var
  526. FileStream: TStream;
  527. begin
  528. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  529. try
  530. Result := FileStream.ReadComponentRes(Instance);
  531. finally
  532. FileStream.Free;
  533. end;
  534. end;
  535. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  536. var
  537. FileStream: TStream;
  538. begin
  539. FileStream := TFileStream.Create(FileName, fmCreate);
  540. try
  541. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  542. finally
  543. FileStream.Free;
  544. end;
  545. end;
  546. Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
  547. Function GetNextName : String; {$ifdef CLASSESINLINE} inline; {$endif CLASSESINLINE}
  548. Var
  549. P : Integer;
  550. CM : Boolean;
  551. begin
  552. P:=Pos('.',APath);
  553. CM:=False;
  554. If (P=0) then
  555. begin
  556. If CStyle then
  557. begin
  558. P:=Pos('->',APath);
  559. CM:=P<>0;
  560. end;
  561. If (P=0) Then
  562. P:=Length(APath)+1;
  563. end;
  564. Result:=Copy(APath,1,P-1);
  565. Delete(APath,1,P+Ord(CM));
  566. end;
  567. Var
  568. C : TComponent;
  569. S : String;
  570. begin
  571. If (APath='') then
  572. Result:=Nil
  573. else
  574. begin
  575. Result:=Root;
  576. While (APath<>'') And (Result<>Nil) do
  577. begin
  578. C:=Result;
  579. S:=Uppercase(GetNextName);
  580. Result:=C.FindComponent(S);
  581. If (Result=Nil) And (S='OWNER') then
  582. Result:=C;
  583. end;
  584. end;
  585. end;
  586. threadvar
  587. GlobalLoaded, GlobalLists: TList;
  588. procedure BeginGlobalLoading;
  589. begin
  590. if not Assigned(GlobalLists) then
  591. GlobalLists := TList.Create;
  592. GlobalLists.Add(GlobalLoaded);
  593. GlobalLoaded := TList.Create;
  594. end;
  595. { Notify all global components that they have been loaded completely }
  596. procedure NotifyGlobalLoading;
  597. var
  598. i: Integer;
  599. begin
  600. for i := 0 to GlobalLoaded.Count - 1 do
  601. TComponent(GlobalLoaded[i]).Loaded;
  602. end;
  603. procedure EndGlobalLoading;
  604. begin
  605. { Free the memory occupied by BeginGlobalLoading }
  606. GlobalLoaded.Free;
  607. GlobalLoaded := TList(GlobalLists.Last);
  608. GlobalLists.Delete(GlobalLists.Count - 1);
  609. if GlobalLists.Count = 0 then
  610. begin
  611. GlobalLists.Free;
  612. GlobalLists := nil;
  613. end;
  614. end;
  615. function CollectionsEqual(C1, C2: TCollection): Boolean;
  616. begin
  617. // !!!: Implement this
  618. CollectionsEqual:=false;
  619. end;
  620. function CollectionsEqual(C1, C2: TCollection; Owner1, Owner2: TComponent): Boolean;
  621. procedure stream_collection(s : tstream;c : tcollection;o : tcomponent);
  622. var
  623. w : twriter;
  624. begin
  625. w:=twriter.create(s,4096);
  626. try
  627. w.root:=o;
  628. w.flookuproot:=o;
  629. w.writecollection(c);
  630. finally
  631. w.free;
  632. end;
  633. end;
  634. var
  635. s1,s2 : tmemorystream;
  636. begin
  637. result:=false;
  638. if (c1.classtype<>c2.classtype) or
  639. (c1.count<>c2.count) then
  640. exit;
  641. s1:=tmemorystream.create;
  642. try
  643. s2:=tmemorystream.create;
  644. try
  645. stream_collection(s1,c1,owner1);
  646. stream_collection(s2,c2,owner2);
  647. result:=(s1.size=s2.size) and (CompareChar(s1.memory,s2.memory,s1.size)=0);
  648. finally
  649. s2.free;
  650. end;
  651. finally
  652. s1.free;
  653. end;
  654. end;
  655. { Object conversion routines }
  656. type
  657. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  658. function CharToOrd(var P: Pointer): Cardinal;
  659. begin
  660. result:= ord(pchar(P)^);
  661. inc(pchar(P));
  662. end;
  663. function WideCharToOrd(var P: Pointer): Cardinal;
  664. begin
  665. result:= ord(pwidechar(P)^);
  666. inc(pwidechar(P));
  667. end;
  668. function Utf8ToOrd(var P:Pointer): Cardinal;
  669. begin
  670. // Should also check for illegal utf8 combinations
  671. Result := Ord(PChar(P)^);
  672. Inc(P);
  673. if (Result and $80) <> 0 then
  674. if (Ord(Result) and %11100000) = %11000000 then begin
  675. Result := ((Result and %00011111) shl 6)
  676. or (ord(PChar(P)^) and %00111111);
  677. Inc(P);
  678. end else if (Ord(Result) and %11110000) = %11100000 then begin
  679. Result := ((Result and %00011111) shl 12)
  680. or ((ord(PChar(P)^) and %00111111) shl 6)
  681. or (ord((PChar(P)+1)^) and %00111111);
  682. Inc(P,2);
  683. end else begin
  684. Result := ((ord(Result) and %00011111) shl 18)
  685. or ((ord(PChar(P)^) and %00111111) shl 12)
  686. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  687. or (ord((PChar(P)+2)^) and %00111111);
  688. Inc(P,3);
  689. end;
  690. end;
  691. procedure ObjectBinaryToText(Input, Output: TStream);
  692. procedure OutStr(s: String);
  693. begin
  694. if Length(s) > 0 then
  695. Output.Write(s[1], Length(s));
  696. end;
  697. procedure OutLn(s: String);
  698. begin
  699. OutStr(s + LineEnding);
  700. end;
  701. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty);
  702. var
  703. res, NewStr: String;
  704. w: Cardinal;
  705. InString, NewInString: Boolean;
  706. begin
  707. if p = nil then begin
  708. res:= '''''';
  709. end
  710. else
  711. begin
  712. res := '';
  713. InString := False;
  714. while P < LastP do
  715. begin
  716. NewInString := InString;
  717. w := CharToOrdfunc(P);
  718. if w = ord('''') then
  719. begin //quote char
  720. if not InString then
  721. NewInString := True;
  722. NewStr := '''''';
  723. end
  724. else if (Ord(w) >= 32) and (Ord(w) < 127) then
  725. begin //printable ascii
  726. if not InString then
  727. NewInString := True;
  728. NewStr := char(w);
  729. end
  730. else
  731. begin //ascii control chars, non ascii
  732. if InString then
  733. NewInString := False;
  734. NewStr := '#' + IntToStr(w);
  735. end;
  736. if NewInString <> InString then
  737. begin
  738. NewStr := '''' + NewStr;
  739. InString := NewInString;
  740. end;
  741. res := res + NewStr;
  742. end;
  743. if InString then
  744. res := res + '''';
  745. end;
  746. OutStr(res);
  747. end;
  748. procedure OutString(s: String);
  749. begin
  750. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd);
  751. end;
  752. procedure OutWString(W: WideString);
  753. begin
  754. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  755. end;
  756. procedure OutUString(W: UnicodeString);
  757. begin
  758. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  759. end;
  760. procedure OutUtf8Str(s: String);
  761. begin
  762. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  763. end;
  764. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  765. begin
  766. Result:=Input.ReadWord;
  767. Result:=LEtoN(Result);
  768. end;
  769. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  770. begin
  771. Result:=Input.ReadDWord;
  772. Result:=LEtoN(Result);
  773. end;
  774. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  775. begin
  776. Input.ReadBuffer(Result,sizeof(Result));
  777. Result:=LEtoN(Result);
  778. end;
  779. {$ifndef FPUNONE}
  780. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  781. function ExtendedToDouble(e : pointer) : double;
  782. var mant : qword;
  783. exp : smallint;
  784. sign : boolean;
  785. d : qword;
  786. begin
  787. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  788. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  789. mant:=LEtoN(mant);
  790. exp:=LetoN(word(exp));
  791. sign:=(exp and $8000)<>0;
  792. if sign then exp:=exp and $7FFF;
  793. case exp of
  794. 0 : mant:=0; //if denormalized, value is too small for double,
  795. //so it's always zero
  796. $7FFF : exp:=2047 //either infinity or NaN
  797. else
  798. begin
  799. dec(exp,16383-1023);
  800. if (exp>=-51) and (exp<=0) then //can be denormalized
  801. begin
  802. mant:=mant shr (-exp);
  803. exp:=0;
  804. end
  805. else
  806. if (exp<-51) or (exp>2046) then //exponent too large.
  807. begin
  808. Result:=0;
  809. exit;
  810. end
  811. else //normalized value
  812. mant:=mant shl 1; //hide most significant bit
  813. end;
  814. end;
  815. d:=word(exp);
  816. d:=d shl 52;
  817. mant:=mant shr 12;
  818. d:=d or mant;
  819. if sign then d:=d or $8000000000000000;
  820. Result:=pdouble(@d)^;
  821. end;
  822. {$ENDIF}
  823. {$endif}
  824. function ReadInt(ValueType: TValueType): Int64;
  825. begin
  826. case ValueType of
  827. vaInt8: Result := ShortInt(Input.ReadByte);
  828. vaInt16: Result := SmallInt(ReadWord);
  829. vaInt32: Result := LongInt(ReadDWord);
  830. vaInt64: Result := Int64(ReadQWord);
  831. end;
  832. end;
  833. function ReadInt: Int64;
  834. begin
  835. Result := ReadInt(TValueType(Input.ReadByte));
  836. end;
  837. {$ifndef FPUNONE}
  838. function ReadExtended : extended;
  839. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  840. var ext : array[0..9] of byte;
  841. {$ENDIF}
  842. begin
  843. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  844. Input.ReadBuffer(ext[0],10);
  845. Result:=ExtendedToDouble(@(ext[0]));
  846. {$ELSE}
  847. Input.ReadBuffer(Result,sizeof(Result));
  848. {$ENDIF}
  849. end;
  850. {$endif}
  851. function ReadSStr: String;
  852. var
  853. len: Byte;
  854. begin
  855. len := Input.ReadByte;
  856. SetLength(Result, len);
  857. if (len > 0) then
  858. Input.ReadBuffer(Result[1], len);
  859. end;
  860. function ReadLStr: String;
  861. var
  862. len: DWord;
  863. begin
  864. len := ReadDWord;
  865. SetLength(Result, len);
  866. if (len > 0) then
  867. Input.ReadBuffer(Result[1], len);
  868. end;
  869. function ReadWStr: WideString;
  870. var
  871. len: DWord;
  872. {$IFDEF ENDIAN_BIG}
  873. i : integer;
  874. {$ENDIF}
  875. begin
  876. len := ReadDWord;
  877. SetLength(Result, len);
  878. if (len > 0) then
  879. begin
  880. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  881. {$IFDEF ENDIAN_BIG}
  882. for i:=1 to len do
  883. Result[i]:=widechar(SwapEndian(word(Result[i])));
  884. {$ENDIF}
  885. end;
  886. end;
  887. function ReadUStr: UnicodeString;
  888. var
  889. len: DWord;
  890. {$IFDEF ENDIAN_BIG}
  891. i : integer;
  892. {$ENDIF}
  893. begin
  894. len := ReadDWord;
  895. SetLength(Result, len);
  896. if (len > 0) then
  897. begin
  898. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  899. {$IFDEF ENDIAN_BIG}
  900. for i:=1 to len do
  901. Result[i]:=widechar(SwapEndian(word(Result[i])));
  902. {$ENDIF}
  903. end;
  904. end;
  905. procedure ReadPropList(indent: String);
  906. procedure ProcessValue(ValueType: TValueType; Indent: String);
  907. procedure ProcessBinary;
  908. var
  909. ToDo, DoNow, i: LongInt;
  910. lbuf: array[0..31] of Byte;
  911. s: String;
  912. begin
  913. ToDo := ReadDWord;
  914. OutLn('{');
  915. while ToDo > 0 do begin
  916. DoNow := ToDo;
  917. if DoNow > 32 then DoNow := 32;
  918. Dec(ToDo, DoNow);
  919. s := Indent + ' ';
  920. Input.ReadBuffer(lbuf, DoNow);
  921. for i := 0 to DoNow - 1 do
  922. s := s + IntToHex(lbuf[i], 2);
  923. OutLn(s);
  924. end;
  925. OutLn(indent + '}');
  926. end;
  927. var
  928. s: String;
  929. { len: LongInt; }
  930. IsFirst: Boolean;
  931. {$ifndef FPUNONE}
  932. ext: Extended;
  933. {$endif}
  934. begin
  935. case ValueType of
  936. vaList: begin
  937. OutStr('(');
  938. IsFirst := True;
  939. while True do begin
  940. ValueType := TValueType(Input.ReadByte);
  941. if ValueType = vaNull then break;
  942. if IsFirst then begin
  943. OutLn('');
  944. IsFirst := False;
  945. end;
  946. OutStr(Indent + ' ');
  947. ProcessValue(ValueType, Indent + ' ');
  948. end;
  949. OutLn(Indent + ')');
  950. end;
  951. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  952. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  953. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  954. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  955. {$ifndef FPUNONE}
  956. vaExtended: begin
  957. ext:=ReadExtended;
  958. Str(ext,S);// Do not use localized strings.
  959. OutLn(S);
  960. end;
  961. {$endif}
  962. vaString: begin
  963. OutString(ReadSStr);
  964. OutLn('');
  965. end;
  966. vaIdent: OutLn(ReadSStr);
  967. vaFalse: OutLn('False');
  968. vaTrue: OutLn('True');
  969. vaBinary: ProcessBinary;
  970. vaSet: begin
  971. OutStr('[');
  972. IsFirst := True;
  973. while True do begin
  974. s := ReadSStr;
  975. if Length(s) = 0 then break;
  976. if not IsFirst then OutStr(', ');
  977. IsFirst := False;
  978. OutStr(s);
  979. end;
  980. OutLn(']');
  981. end;
  982. vaLString:
  983. begin
  984. OutString(ReadLStr);
  985. OutLn('');
  986. end;
  987. vaWString:
  988. begin
  989. OutWString(ReadWStr);
  990. OutLn('');
  991. end;
  992. vaUString:
  993. begin
  994. OutWString(ReadWStr);
  995. OutLn('');
  996. end;
  997. vaNil:
  998. OutLn('nil');
  999. vaCollection: begin
  1000. OutStr('<');
  1001. while Input.ReadByte <> 0 do begin
  1002. OutLn(Indent);
  1003. Input.Seek(-1, soFromCurrent);
  1004. OutStr(indent + ' item');
  1005. ValueType := TValueType(Input.ReadByte);
  1006. if ValueType <> vaList then
  1007. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1008. OutLn('');
  1009. ReadPropList(indent + ' ');
  1010. OutStr(indent + ' end');
  1011. end;
  1012. OutLn('>');
  1013. end;
  1014. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1015. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1016. vaDate: begin OutLn('!!Date!!'); exit end;}
  1017. vaUTF8String: begin
  1018. OutUtf8Str(ReadLStr);
  1019. OutLn('');
  1020. end;
  1021. else
  1022. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1023. end;
  1024. end;
  1025. begin
  1026. while Input.ReadByte <> 0 do begin
  1027. Input.Seek(-1, soFromCurrent);
  1028. OutStr(indent + ReadSStr + ' = ');
  1029. ProcessValue(TValueType(Input.ReadByte), Indent);
  1030. end;
  1031. end;
  1032. procedure ReadObject(indent: String);
  1033. var
  1034. b: Byte;
  1035. ObjClassName, ObjName: String;
  1036. ChildPos: LongInt;
  1037. begin
  1038. // Check for FilerFlags
  1039. b := Input.ReadByte;
  1040. if (b and $f0) = $f0 then begin
  1041. if (b and 2) <> 0 then ChildPos := ReadInt;
  1042. end else begin
  1043. b := 0;
  1044. Input.Seek(-1, soFromCurrent);
  1045. end;
  1046. ObjClassName := ReadSStr;
  1047. ObjName := ReadSStr;
  1048. OutStr(Indent);
  1049. if (b and 1) <> 0 then OutStr('inherited')
  1050. else
  1051. if (b and 4) <> 0 then OutStr('inline')
  1052. else OutStr('object');
  1053. OutStr(' ');
  1054. if ObjName <> '' then
  1055. OutStr(ObjName + ': ');
  1056. OutStr(ObjClassName);
  1057. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1058. OutLn('');
  1059. ReadPropList(indent + ' ');
  1060. while Input.ReadByte <> 0 do begin
  1061. Input.Seek(-1, soFromCurrent);
  1062. ReadObject(indent + ' ');
  1063. end;
  1064. OutLn(indent + 'end');
  1065. end;
  1066. type
  1067. PLongWord = ^LongWord;
  1068. const
  1069. signature: PChar = 'TPF0';
  1070. begin
  1071. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1072. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1073. ReadObject('');
  1074. end;
  1075. procedure ObjectTextToBinary(Input, Output: TStream);
  1076. var
  1077. parser: TParser;
  1078. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1079. begin
  1080. w:=NtoLE(w);
  1081. Output.WriteWord(w);
  1082. end;
  1083. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1084. begin
  1085. lw:=NtoLE(lw);
  1086. Output.WriteDWord(lw);
  1087. end;
  1088. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1089. begin
  1090. qw:=NtoLE(qw);
  1091. Output.WriteBuffer(qw,sizeof(qword));
  1092. end;
  1093. {$ifndef FPUNONE}
  1094. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1095. procedure DoubleToExtended(d : double; e : pointer);
  1096. var mant : qword;
  1097. exp : smallint;
  1098. sign : boolean;
  1099. begin
  1100. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1101. exp :=(qword(d) shr 52) and $7FF;
  1102. sign:=(qword(d) and $8000000000000000)<>0;
  1103. case exp of
  1104. 0 : begin
  1105. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1106. begin
  1107. exp:=16383-1022;
  1108. while (mant and $8000000000000000)=0 do
  1109. begin
  1110. dec(exp);
  1111. mant:=mant shl 1;
  1112. end;
  1113. dec(exp); //don't shift, most significant bit is not hidden in extended
  1114. end;
  1115. end;
  1116. 2047 : exp:=$7FFF //either infinity or NaN
  1117. else
  1118. begin
  1119. inc(exp,16383-1023);
  1120. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1121. end;
  1122. end;
  1123. if sign then exp:=exp or $8000;
  1124. mant:=NtoLE(mant);
  1125. exp:=NtoLE(word(exp));
  1126. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1127. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1128. end;
  1129. {$ENDIF}
  1130. procedure WriteExtended(e : extended);
  1131. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1132. var ext : array[0..9] of byte;
  1133. {$ENDIF}
  1134. begin
  1135. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1136. DoubleToExtended(e,@(ext[0]));
  1137. Output.WriteBuffer(ext[0],10);
  1138. {$ELSE}
  1139. Output.WriteBuffer(e,sizeof(e));
  1140. {$ENDIF}
  1141. end;
  1142. {$endif}
  1143. procedure WriteString(s: String);
  1144. var size : byte;
  1145. begin
  1146. if length(s)>255 then size:=255
  1147. else size:=length(s);
  1148. Output.WriteByte(size);
  1149. if Length(s) > 0 then
  1150. Output.WriteBuffer(s[1], size);
  1151. end;
  1152. procedure WriteLString(Const s: String);
  1153. begin
  1154. WriteDWord(Length(s));
  1155. if Length(s) > 0 then
  1156. Output.WriteBuffer(s[1], Length(s));
  1157. end;
  1158. procedure WriteWString(Const s: WideString);
  1159. var len : longword;
  1160. {$IFDEF ENDIAN_BIG}
  1161. i : integer;
  1162. ws : widestring;
  1163. {$ENDIF}
  1164. begin
  1165. len:=Length(s);
  1166. WriteDWord(len);
  1167. if len > 0 then
  1168. begin
  1169. {$IFDEF ENDIAN_BIG}
  1170. setlength(ws,len);
  1171. for i:=1 to len do
  1172. ws[i]:=widechar(SwapEndian(word(s[i])));
  1173. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1174. {$ELSE}
  1175. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1176. {$ENDIF}
  1177. end;
  1178. end;
  1179. procedure WriteInteger(value: Int64);
  1180. begin
  1181. if (value >= -128) and (value <= 127) then begin
  1182. Output.WriteByte(Ord(vaInt8));
  1183. Output.WriteByte(byte(value));
  1184. end else if (value >= -32768) and (value <= 32767) then begin
  1185. Output.WriteByte(Ord(vaInt16));
  1186. WriteWord(word(value));
  1187. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1188. Output.WriteByte(Ord(vaInt32));
  1189. WriteDWord(longword(value));
  1190. end else begin
  1191. Output.WriteByte(ord(vaInt64));
  1192. WriteQWord(qword(value));
  1193. end;
  1194. end;
  1195. procedure ProcessWideString(const left : widestring);
  1196. var ws : widestring;
  1197. begin
  1198. ws:=left+parser.TokenWideString;
  1199. while parser.NextToken = '+' do
  1200. begin
  1201. parser.NextToken; // Get next string fragment
  1202. if not (parser.Token in [toString,toWString]) then
  1203. parser.CheckToken(toWString);
  1204. ws:=ws+parser.TokenWideString;
  1205. end;
  1206. Output.WriteByte(Ord(vaWstring));
  1207. WriteWString(ws);
  1208. end;
  1209. procedure ProcessProperty; forward;
  1210. procedure ProcessValue;
  1211. var
  1212. {$ifndef FPUNONE}
  1213. flt: Extended;
  1214. {$endif}
  1215. s: String;
  1216. stream: TMemoryStream;
  1217. begin
  1218. case parser.Token of
  1219. toInteger:
  1220. begin
  1221. WriteInteger(parser.TokenInt);
  1222. parser.NextToken;
  1223. end;
  1224. {$ifndef FPUNONE}
  1225. toFloat:
  1226. begin
  1227. Output.WriteByte(Ord(vaExtended));
  1228. flt := Parser.TokenFloat;
  1229. WriteExtended(flt);
  1230. parser.NextToken;
  1231. end;
  1232. {$endif}
  1233. toString:
  1234. begin
  1235. s := parser.TokenString;
  1236. while parser.NextToken = '+' do
  1237. begin
  1238. parser.NextToken; // Get next string fragment
  1239. case parser.Token of
  1240. toString : s:=s+parser.TokenString;
  1241. toWString : begin
  1242. ProcessWideString(s);
  1243. exit;
  1244. end
  1245. else parser.CheckToken(toString);
  1246. end;
  1247. end;
  1248. if (length(S)>255) then
  1249. begin
  1250. Output.WriteByte(Ord(vaLString));
  1251. WriteLString(S);
  1252. end
  1253. else
  1254. begin
  1255. Output.WriteByte(Ord(vaString));
  1256. WriteString(s);
  1257. end;
  1258. end;
  1259. toWString:
  1260. ProcessWideString('');
  1261. toSymbol:
  1262. begin
  1263. if CompareText(parser.TokenString, 'True') = 0 then
  1264. Output.WriteByte(Ord(vaTrue))
  1265. else if CompareText(parser.TokenString, 'False') = 0 then
  1266. Output.WriteByte(Ord(vaFalse))
  1267. else if CompareText(parser.TokenString, 'nil') = 0 then
  1268. Output.WriteByte(Ord(vaNil))
  1269. else
  1270. begin
  1271. Output.WriteByte(Ord(vaIdent));
  1272. WriteString(parser.TokenComponentIdent);
  1273. end;
  1274. Parser.NextToken;
  1275. end;
  1276. // Set
  1277. '[':
  1278. begin
  1279. parser.NextToken;
  1280. Output.WriteByte(Ord(vaSet));
  1281. if parser.Token <> ']' then
  1282. while True do
  1283. begin
  1284. parser.CheckToken(toSymbol);
  1285. WriteString(parser.TokenString);
  1286. parser.NextToken;
  1287. if parser.Token = ']' then
  1288. break;
  1289. parser.CheckToken(',');
  1290. parser.NextToken;
  1291. end;
  1292. Output.WriteByte(0);
  1293. parser.NextToken;
  1294. end;
  1295. // List
  1296. '(':
  1297. begin
  1298. parser.NextToken;
  1299. Output.WriteByte(Ord(vaList));
  1300. while parser.Token <> ')' do
  1301. ProcessValue;
  1302. Output.WriteByte(0);
  1303. parser.NextToken;
  1304. end;
  1305. // Collection
  1306. '<':
  1307. begin
  1308. parser.NextToken;
  1309. Output.WriteByte(Ord(vaCollection));
  1310. while parser.Token <> '>' do
  1311. begin
  1312. parser.CheckTokenSymbol('item');
  1313. parser.NextToken;
  1314. // ConvertOrder
  1315. Output.WriteByte(Ord(vaList));
  1316. while not parser.TokenSymbolIs('end') do
  1317. ProcessProperty;
  1318. parser.NextToken; // Skip 'end'
  1319. Output.WriteByte(0);
  1320. end;
  1321. Output.WriteByte(0);
  1322. parser.NextToken;
  1323. end;
  1324. // Binary data
  1325. '{':
  1326. begin
  1327. Output.WriteByte(Ord(vaBinary));
  1328. stream := TMemoryStream.Create;
  1329. try
  1330. parser.HexToBinary(stream);
  1331. WriteDWord(stream.Size);
  1332. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1333. finally
  1334. stream.Free;
  1335. end;
  1336. parser.NextToken;
  1337. end;
  1338. else
  1339. parser.Error(SInvalidProperty);
  1340. end;
  1341. end;
  1342. procedure ProcessProperty;
  1343. var
  1344. name: String;
  1345. begin
  1346. // Get name of property
  1347. parser.CheckToken(toSymbol);
  1348. name := parser.TokenString;
  1349. while True do begin
  1350. parser.NextToken;
  1351. if parser.Token <> '.' then break;
  1352. parser.NextToken;
  1353. parser.CheckToken(toSymbol);
  1354. name := name + '.' + parser.TokenString;
  1355. end;
  1356. WriteString(name);
  1357. parser.CheckToken('=');
  1358. parser.NextToken;
  1359. ProcessValue;
  1360. end;
  1361. procedure ProcessObject;
  1362. var
  1363. Flags: Byte;
  1364. ObjectName, ObjectType: String;
  1365. ChildPos: Integer;
  1366. begin
  1367. if parser.TokenSymbolIs('OBJECT') then
  1368. Flags :=0 { IsInherited := False }
  1369. else begin
  1370. if parser.TokenSymbolIs('INHERITED') then
  1371. Flags := 1 { IsInherited := True; }
  1372. else begin
  1373. parser.CheckTokenSymbol('INLINE');
  1374. Flags := 4;
  1375. end;
  1376. end;
  1377. parser.NextToken;
  1378. parser.CheckToken(toSymbol);
  1379. ObjectName := '';
  1380. ObjectType := parser.TokenString;
  1381. parser.NextToken;
  1382. if parser.Token = ':' then begin
  1383. parser.NextToken;
  1384. parser.CheckToken(toSymbol);
  1385. ObjectName := ObjectType;
  1386. ObjectType := parser.TokenString;
  1387. parser.NextToken;
  1388. if parser.Token = '[' then begin
  1389. parser.NextToken;
  1390. ChildPos := parser.TokenInt;
  1391. parser.NextToken;
  1392. parser.CheckToken(']');
  1393. parser.NextToken;
  1394. Flags := Flags or 2;
  1395. end;
  1396. end;
  1397. if Flags <> 0 then begin
  1398. Output.WriteByte($f0 or Flags);
  1399. if (Flags and 2) <> 0 then
  1400. WriteInteger(ChildPos);
  1401. end;
  1402. WriteString(ObjectType);
  1403. WriteString(ObjectName);
  1404. // Convert property list
  1405. while not (parser.TokenSymbolIs('END') or
  1406. parser.TokenSymbolIs('OBJECT') or
  1407. parser.TokenSymbolIs('INHERITED') or
  1408. parser.TokenSymbolIs('INLINE')) do
  1409. ProcessProperty;
  1410. Output.WriteByte(0); // Terminate property list
  1411. // Convert child objects
  1412. while not parser.TokenSymbolIs('END') do ProcessObject;
  1413. parser.NextToken; // Skip end token
  1414. Output.WriteByte(0); // Terminate property list
  1415. end;
  1416. const
  1417. signature: PChar = 'TPF0';
  1418. begin
  1419. parser := TParser.Create(Input);
  1420. try
  1421. Output.WriteBuffer(signature[0], 4);
  1422. ProcessObject;
  1423. finally
  1424. parser.Free;
  1425. end;
  1426. end;
  1427. procedure ObjectResourceToText(Input, Output: TStream);
  1428. begin
  1429. Input.ReadResHeader;
  1430. ObjectBinaryToText(Input, Output);
  1431. end;
  1432. procedure ObjectTextToResource(Input, Output: TStream);
  1433. var
  1434. StartPos, FixupInfo: LongInt;
  1435. parser: TParser;
  1436. name: String;
  1437. begin
  1438. // Get form type name
  1439. StartPos := Input.Position;
  1440. parser := TParser.Create(Input);
  1441. try
  1442. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1443. parser.NextToken;
  1444. parser.CheckToken(toSymbol);
  1445. parser.NextToken;
  1446. parser.CheckToken(':');
  1447. parser.NextToken;
  1448. parser.CheckToken(toSymbol);
  1449. name := parser.TokenString;
  1450. finally
  1451. parser.Free;
  1452. Input.Position := StartPos;
  1453. end;
  1454. name := UpperCase(name);
  1455. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1456. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1457. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1458. end;
  1459. { Utility routines }
  1460. function LineStart(Buffer, BufPos: PChar): PChar;
  1461. begin
  1462. Result := BufPos;
  1463. while Result > Buffer do begin
  1464. Dec(Result);
  1465. if Result[0] = #10 then break;
  1466. end;
  1467. end;
  1468. procedure CommonInit;
  1469. begin
  1470. InitCriticalSection(SynchronizeCritSect);
  1471. ExecuteEvent:=RtlEventCreate;
  1472. SynchronizeTimeoutEvent:=RtlEventCreate;
  1473. DoSynchronizeMethod:=false;
  1474. MainThreadID:=GetCurrentThreadID;
  1475. InitCriticalsection(ResolveSection);
  1476. InitHandlerList:=Nil;
  1477. FindGlobalComponentList:=nil;
  1478. IntConstList := TThreadList.Create;
  1479. ClassList := TThreadList.Create;
  1480. ClassAliasList := TStringList.Create;
  1481. { on unix this maps to a simple rw synchornizer }
  1482. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1483. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1484. end;
  1485. procedure CommonCleanup;
  1486. var
  1487. i: Integer;
  1488. begin
  1489. GlobalNameSpace.BeginWrite;
  1490. with IntConstList.LockList do
  1491. try
  1492. for i := 0 to Count - 1 do
  1493. TIntConst(Items[I]).Free;
  1494. finally
  1495. IntConstList.UnlockList;
  1496. end;
  1497. IntConstList.Free;
  1498. ClassList.Free;
  1499. ClassAliasList.Free;
  1500. RemoveFixupReferences(nil, '');
  1501. DoneCriticalsection(ResolveSection);
  1502. GlobalLists.Free;
  1503. ComponentPages.Free;
  1504. FreeAndNil(NeedResolving);
  1505. { GlobalNameSpace is an interface so this is enough }
  1506. GlobalNameSpace:=nil;
  1507. if (InitHandlerList<>Nil) then
  1508. for i := 0 to InitHandlerList.Count - 1 do
  1509. TInitHandler(InitHandlerList.Items[I]).Free;
  1510. InitHandlerList.Free;
  1511. InitHandlerList:=Nil;
  1512. FindGlobalComponentList.Free;
  1513. FindGlobalComponentList:=nil;
  1514. DoneCriticalSection(SynchronizeCritSect);
  1515. RtlEventDestroy(ExecuteEvent);
  1516. RtlEventDestroy(SynchronizeTimeoutEvent);
  1517. end;
  1518. { TFiler implementation }
  1519. {$i filer.inc}
  1520. { TReader implementation }
  1521. {$i reader.inc}
  1522. { TWriter implementations }
  1523. {$i writer.inc}
  1524. {$i twriter.inc}