2
0

classes.inc 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  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. if c1.count = 0 then
  642. begin
  643. result:= true;
  644. exit;
  645. end;
  646. s1:=tmemorystream.create;
  647. try
  648. s2:=tmemorystream.create;
  649. try
  650. stream_collection(s1,c1,owner1);
  651. stream_collection(s2,c2,owner2);
  652. result:=(s1.size=s2.size) and (CompareChar(s1.memory^,s2.memory^,s1.size)=0);
  653. finally
  654. s2.free;
  655. end;
  656. finally
  657. s1.free;
  658. end;
  659. end;
  660. { Object conversion routines }
  661. type
  662. CharToOrdFuncty = Function(var charpo: Pointer): Cardinal;
  663. function CharToOrd(var P: Pointer): Cardinal;
  664. begin
  665. result:= ord(pchar(P)^);
  666. inc(pchar(P));
  667. end;
  668. function WideCharToOrd(var P: Pointer): Cardinal;
  669. begin
  670. result:= ord(pwidechar(P)^);
  671. inc(pwidechar(P));
  672. end;
  673. function Utf8ToOrd(var P:Pointer): Cardinal;
  674. begin
  675. // Should also check for illegal utf8 combinations
  676. Result := Ord(PChar(P)^);
  677. Inc(P);
  678. if (Result and $80) <> 0 then
  679. if (Ord(Result) and %11100000) = %11000000 then begin
  680. Result := ((Result and %00011111) shl 6)
  681. or (ord(PChar(P)^) and %00111111);
  682. Inc(P);
  683. end else if (Ord(Result) and %11110000) = %11100000 then begin
  684. Result := ((Result and %00011111) shl 12)
  685. or ((ord(PChar(P)^) and %00111111) shl 6)
  686. or (ord((PChar(P)+1)^) and %00111111);
  687. Inc(P,2);
  688. end else begin
  689. Result := ((ord(Result) and %00011111) shl 18)
  690. or ((ord(PChar(P)^) and %00111111) shl 12)
  691. or ((ord((PChar(P)+1)^) and %00111111) shl 6)
  692. or (ord((PChar(P)+2)^) and %00111111);
  693. Inc(P,3);
  694. end;
  695. end;
  696. procedure ObjectBinaryToText(Input, Output: TStream);
  697. procedure OutStr(s: String);
  698. begin
  699. if Length(s) > 0 then
  700. Output.Write(s[1], Length(s));
  701. end;
  702. procedure OutLn(s: String);
  703. begin
  704. OutStr(s + LineEnding);
  705. end;
  706. procedure Outchars(P, LastP : Pointer; CharToOrdFunc: CharToOrdFuncty);
  707. var
  708. res, NewStr: String;
  709. w: Cardinal;
  710. InString, NewInString: Boolean;
  711. begin
  712. if p = nil then begin
  713. res:= '''''';
  714. end
  715. else
  716. begin
  717. res := '';
  718. InString := False;
  719. while P < LastP do
  720. begin
  721. NewInString := InString;
  722. w := CharToOrdfunc(P);
  723. if w = ord('''') then
  724. begin //quote char
  725. if not InString then
  726. NewInString := True;
  727. NewStr := '''''';
  728. end
  729. else if (Ord(w) >= 32) and (Ord(w) < 127) then
  730. begin //printable ascii
  731. if not InString then
  732. NewInString := True;
  733. NewStr := char(w);
  734. end
  735. else
  736. begin //ascii control chars, non ascii
  737. if InString then
  738. NewInString := False;
  739. NewStr := '#' + IntToStr(w);
  740. end;
  741. if NewInString <> InString then
  742. begin
  743. NewStr := '''' + NewStr;
  744. InString := NewInString;
  745. end;
  746. res := res + NewStr;
  747. end;
  748. if InString then
  749. res := res + '''';
  750. end;
  751. OutStr(res);
  752. end;
  753. procedure OutString(s: String);
  754. begin
  755. OutChars(Pointer(S),PChar(S)+Length(S),@CharToOrd);
  756. end;
  757. procedure OutWString(W: WideString);
  758. begin
  759. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  760. end;
  761. procedure OutUString(W: UnicodeString);
  762. begin
  763. OutChars(Pointer(W),pwidechar(W)+Length(W),@WideCharToOrd);
  764. end;
  765. procedure OutUtf8Str(s: String);
  766. begin
  767. OutChars(Pointer(S),PChar(S)+Length(S),@Utf8ToOrd);
  768. end;
  769. function ReadWord : word; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  770. begin
  771. Result:=Input.ReadWord;
  772. Result:=LEtoN(Result);
  773. end;
  774. function ReadDWord : longword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  775. begin
  776. Result:=Input.ReadDWord;
  777. Result:=LEtoN(Result);
  778. end;
  779. function ReadQWord : qword; {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  780. begin
  781. Input.ReadBuffer(Result,sizeof(Result));
  782. Result:=LEtoN(Result);
  783. end;
  784. {$ifndef FPUNONE}
  785. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  786. function ExtendedToDouble(e : pointer) : double;
  787. var mant : qword;
  788. exp : smallint;
  789. sign : boolean;
  790. d : qword;
  791. begin
  792. move(pbyte(e)[0],mant,8); //mantissa : bytes 0..7
  793. move(pbyte(e)[8],exp,2); //exponent and sign: bytes 8..9
  794. mant:=LEtoN(mant);
  795. exp:=LetoN(word(exp));
  796. sign:=(exp and $8000)<>0;
  797. if sign then exp:=exp and $7FFF;
  798. case exp of
  799. 0 : mant:=0; //if denormalized, value is too small for double,
  800. //so it's always zero
  801. $7FFF : exp:=2047 //either infinity or NaN
  802. else
  803. begin
  804. dec(exp,16383-1023);
  805. if (exp>=-51) and (exp<=0) then //can be denormalized
  806. begin
  807. mant:=mant shr (-exp);
  808. exp:=0;
  809. end
  810. else
  811. if (exp<-51) or (exp>2046) then //exponent too large.
  812. begin
  813. Result:=0;
  814. exit;
  815. end
  816. else //normalized value
  817. mant:=mant shl 1; //hide most significant bit
  818. end;
  819. end;
  820. d:=word(exp);
  821. d:=d shl 52;
  822. mant:=mant shr 12;
  823. d:=d or mant;
  824. if sign then d:=d or $8000000000000000;
  825. Result:=pdouble(@d)^;
  826. end;
  827. {$ENDIF}
  828. {$endif}
  829. function ReadInt(ValueType: TValueType): Int64;
  830. begin
  831. case ValueType of
  832. vaInt8: Result := ShortInt(Input.ReadByte);
  833. vaInt16: Result := SmallInt(ReadWord);
  834. vaInt32: Result := LongInt(ReadDWord);
  835. vaInt64: Result := Int64(ReadQWord);
  836. end;
  837. end;
  838. function ReadInt: Int64;
  839. begin
  840. Result := ReadInt(TValueType(Input.ReadByte));
  841. end;
  842. {$ifndef FPUNONE}
  843. function ReadExtended : extended;
  844. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  845. var ext : array[0..9] of byte;
  846. {$ENDIF}
  847. begin
  848. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  849. Input.ReadBuffer(ext[0],10);
  850. Result:=ExtendedToDouble(@(ext[0]));
  851. {$ELSE}
  852. Input.ReadBuffer(Result,sizeof(Result));
  853. {$ENDIF}
  854. end;
  855. {$endif}
  856. function ReadSStr: String;
  857. var
  858. len: Byte;
  859. begin
  860. len := Input.ReadByte;
  861. SetLength(Result, len);
  862. if (len > 0) then
  863. Input.ReadBuffer(Result[1], len);
  864. end;
  865. function ReadLStr: String;
  866. var
  867. len: DWord;
  868. begin
  869. len := ReadDWord;
  870. SetLength(Result, len);
  871. if (len > 0) then
  872. Input.ReadBuffer(Result[1], len);
  873. end;
  874. function ReadWStr: WideString;
  875. var
  876. len: DWord;
  877. {$IFDEF ENDIAN_BIG}
  878. i : integer;
  879. {$ENDIF}
  880. begin
  881. len := ReadDWord;
  882. SetLength(Result, len);
  883. if (len > 0) then
  884. begin
  885. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  886. {$IFDEF ENDIAN_BIG}
  887. for i:=1 to len do
  888. Result[i]:=widechar(SwapEndian(word(Result[i])));
  889. {$ENDIF}
  890. end;
  891. end;
  892. function ReadUStr: UnicodeString;
  893. var
  894. len: DWord;
  895. {$IFDEF ENDIAN_BIG}
  896. i : integer;
  897. {$ENDIF}
  898. begin
  899. len := ReadDWord;
  900. SetLength(Result, len);
  901. if (len > 0) then
  902. begin
  903. Input.ReadBuffer(Pointer(@Result[1])^, len*2);
  904. {$IFDEF ENDIAN_BIG}
  905. for i:=1 to len do
  906. Result[i]:=widechar(SwapEndian(word(Result[i])));
  907. {$ENDIF}
  908. end;
  909. end;
  910. procedure ReadPropList(indent: String);
  911. procedure ProcessValue(ValueType: TValueType; Indent: String);
  912. procedure ProcessBinary;
  913. var
  914. ToDo, DoNow, i: LongInt;
  915. lbuf: array[0..31] of Byte;
  916. s: String;
  917. begin
  918. ToDo := ReadDWord;
  919. OutLn('{');
  920. while ToDo > 0 do begin
  921. DoNow := ToDo;
  922. if DoNow > 32 then DoNow := 32;
  923. Dec(ToDo, DoNow);
  924. s := Indent + ' ';
  925. Input.ReadBuffer(lbuf, DoNow);
  926. for i := 0 to DoNow - 1 do
  927. s := s + IntToHex(lbuf[i], 2);
  928. OutLn(s);
  929. end;
  930. OutLn(indent + '}');
  931. end;
  932. var
  933. s: String;
  934. { len: LongInt; }
  935. IsFirst: Boolean;
  936. {$ifndef FPUNONE}
  937. ext: Extended;
  938. {$endif}
  939. begin
  940. case ValueType of
  941. vaList: begin
  942. OutStr('(');
  943. IsFirst := True;
  944. while True do begin
  945. ValueType := TValueType(Input.ReadByte);
  946. if ValueType = vaNull then break;
  947. if IsFirst then begin
  948. OutLn('');
  949. IsFirst := False;
  950. end;
  951. OutStr(Indent + ' ');
  952. ProcessValue(ValueType, Indent + ' ');
  953. end;
  954. OutLn(Indent + ')');
  955. end;
  956. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  957. vaInt16: OutLn( IntToStr(SmallInt(ReadWord)));
  958. vaInt32: OutLn(IntToStr(LongInt(ReadDWord)));
  959. vaInt64: OutLn(IntToStr(Int64(ReadQWord)));
  960. {$ifndef FPUNONE}
  961. vaExtended: begin
  962. ext:=ReadExtended;
  963. Str(ext,S);// Do not use localized strings.
  964. OutLn(S);
  965. end;
  966. {$endif}
  967. vaString: begin
  968. OutString(ReadSStr);
  969. OutLn('');
  970. end;
  971. vaIdent: OutLn(ReadSStr);
  972. vaFalse: OutLn('False');
  973. vaTrue: OutLn('True');
  974. vaBinary: ProcessBinary;
  975. vaSet: begin
  976. OutStr('[');
  977. IsFirst := True;
  978. while True do begin
  979. s := ReadSStr;
  980. if Length(s) = 0 then break;
  981. if not IsFirst then OutStr(', ');
  982. IsFirst := False;
  983. OutStr(s);
  984. end;
  985. OutLn(']');
  986. end;
  987. vaLString:
  988. begin
  989. OutString(ReadLStr);
  990. OutLn('');
  991. end;
  992. vaWString:
  993. begin
  994. OutWString(ReadWStr);
  995. OutLn('');
  996. end;
  997. vaUString:
  998. begin
  999. OutWString(ReadWStr);
  1000. OutLn('');
  1001. end;
  1002. vaNil:
  1003. OutLn('nil');
  1004. vaCollection: begin
  1005. OutStr('<');
  1006. while Input.ReadByte <> 0 do begin
  1007. OutLn(Indent);
  1008. Input.Seek(-1, soFromCurrent);
  1009. OutStr(indent + ' item');
  1010. ValueType := TValueType(Input.ReadByte);
  1011. if ValueType <> vaList then
  1012. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  1013. OutLn('');
  1014. ReadPropList(indent + ' ');
  1015. OutStr(indent + ' end');
  1016. end;
  1017. OutLn('>');
  1018. end;
  1019. {vaSingle: begin OutLn('!!Single!!'); exit end;
  1020. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  1021. vaDate: begin OutLn('!!Date!!'); exit end;}
  1022. vaUTF8String: begin
  1023. OutUtf8Str(ReadLStr);
  1024. OutLn('');
  1025. end;
  1026. else
  1027. Raise EReadError.CreateFmt(SErrInvalidPropertyType,[Ord(ValueType)]);
  1028. end;
  1029. end;
  1030. begin
  1031. while Input.ReadByte <> 0 do begin
  1032. Input.Seek(-1, soFromCurrent);
  1033. OutStr(indent + ReadSStr + ' = ');
  1034. ProcessValue(TValueType(Input.ReadByte), Indent);
  1035. end;
  1036. end;
  1037. procedure ReadObject(indent: String);
  1038. var
  1039. b: Byte;
  1040. ObjClassName, ObjName: String;
  1041. ChildPos: LongInt;
  1042. begin
  1043. // Check for FilerFlags
  1044. b := Input.ReadByte;
  1045. if (b and $f0) = $f0 then begin
  1046. if (b and 2) <> 0 then ChildPos := ReadInt;
  1047. end else begin
  1048. b := 0;
  1049. Input.Seek(-1, soFromCurrent);
  1050. end;
  1051. ObjClassName := ReadSStr;
  1052. ObjName := ReadSStr;
  1053. OutStr(Indent);
  1054. if (b and 1) <> 0 then OutStr('inherited')
  1055. else
  1056. if (b and 4) <> 0 then OutStr('inline')
  1057. else OutStr('object');
  1058. OutStr(' ');
  1059. if ObjName <> '' then
  1060. OutStr(ObjName + ': ');
  1061. OutStr(ObjClassName);
  1062. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  1063. OutLn('');
  1064. ReadPropList(indent + ' ');
  1065. while Input.ReadByte <> 0 do begin
  1066. Input.Seek(-1, soFromCurrent);
  1067. ReadObject(indent + ' ');
  1068. end;
  1069. OutLn(indent + 'end');
  1070. end;
  1071. type
  1072. PLongWord = ^LongWord;
  1073. const
  1074. signature: PChar = 'TPF0';
  1075. begin
  1076. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  1077. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  1078. ReadObject('');
  1079. end;
  1080. procedure ObjectTextToBinary(Input, Output: TStream);
  1081. var
  1082. parser: TParser;
  1083. procedure WriteWord(w : word); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1084. begin
  1085. w:=NtoLE(w);
  1086. Output.WriteWord(w);
  1087. end;
  1088. procedure WriteDWord(lw : longword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1089. begin
  1090. lw:=NtoLE(lw);
  1091. Output.WriteDWord(lw);
  1092. end;
  1093. procedure WriteQWord(qw : qword); {$ifdef CLASSESINLINE}inline;{$endif CLASSESINLINE}
  1094. begin
  1095. qw:=NtoLE(qw);
  1096. Output.WriteBuffer(qw,sizeof(qword));
  1097. end;
  1098. {$ifndef FPUNONE}
  1099. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1100. procedure DoubleToExtended(d : double; e : pointer);
  1101. var mant : qword;
  1102. exp : smallint;
  1103. sign : boolean;
  1104. begin
  1105. mant:=(qword(d) and $000FFFFFFFFFFFFF) shl 12;
  1106. exp :=(qword(d) shr 52) and $7FF;
  1107. sign:=(qword(d) and $8000000000000000)<>0;
  1108. case exp of
  1109. 0 : begin
  1110. if mant<>0 then //denormalized value: hidden bit is 0. normalize it
  1111. begin
  1112. exp:=16383-1022;
  1113. while (mant and $8000000000000000)=0 do
  1114. begin
  1115. dec(exp);
  1116. mant:=mant shl 1;
  1117. end;
  1118. dec(exp); //don't shift, most significant bit is not hidden in extended
  1119. end;
  1120. end;
  1121. 2047 : exp:=$7FFF //either infinity or NaN
  1122. else
  1123. begin
  1124. inc(exp,16383-1023);
  1125. mant:=(mant shr 1) or $8000000000000000; //unhide hidden bit
  1126. end;
  1127. end;
  1128. if sign then exp:=exp or $8000;
  1129. mant:=NtoLE(mant);
  1130. exp:=NtoLE(word(exp));
  1131. move(mant,pbyte(e)[0],8); //mantissa : bytes 0..7
  1132. move(exp,pbyte(e)[8],2); //exponent and sign: bytes 8..9
  1133. end;
  1134. {$ENDIF}
  1135. procedure WriteExtended(e : extended);
  1136. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1137. var ext : array[0..9] of byte;
  1138. {$ENDIF}
  1139. begin
  1140. {$IFNDEF FPC_HAS_TYPE_EXTENDED}
  1141. DoubleToExtended(e,@(ext[0]));
  1142. Output.WriteBuffer(ext[0],10);
  1143. {$ELSE}
  1144. Output.WriteBuffer(e,sizeof(e));
  1145. {$ENDIF}
  1146. end;
  1147. {$endif}
  1148. procedure WriteString(s: String);
  1149. var size : byte;
  1150. begin
  1151. if length(s)>255 then size:=255
  1152. else size:=length(s);
  1153. Output.WriteByte(size);
  1154. if Length(s) > 0 then
  1155. Output.WriteBuffer(s[1], size);
  1156. end;
  1157. procedure WriteLString(Const s: String);
  1158. begin
  1159. WriteDWord(Length(s));
  1160. if Length(s) > 0 then
  1161. Output.WriteBuffer(s[1], Length(s));
  1162. end;
  1163. procedure WriteWString(Const s: WideString);
  1164. var len : longword;
  1165. {$IFDEF ENDIAN_BIG}
  1166. i : integer;
  1167. ws : widestring;
  1168. {$ENDIF}
  1169. begin
  1170. len:=Length(s);
  1171. WriteDWord(len);
  1172. if len > 0 then
  1173. begin
  1174. {$IFDEF ENDIAN_BIG}
  1175. setlength(ws,len);
  1176. for i:=1 to len do
  1177. ws[i]:=widechar(SwapEndian(word(s[i])));
  1178. Output.WriteBuffer(ws[1], len*sizeof(widechar));
  1179. {$ELSE}
  1180. Output.WriteBuffer(s[1], len*sizeof(widechar));
  1181. {$ENDIF}
  1182. end;
  1183. end;
  1184. procedure WriteInteger(value: Int64);
  1185. begin
  1186. if (value >= -128) and (value <= 127) then begin
  1187. Output.WriteByte(Ord(vaInt8));
  1188. Output.WriteByte(byte(value));
  1189. end else if (value >= -32768) and (value <= 32767) then begin
  1190. Output.WriteByte(Ord(vaInt16));
  1191. WriteWord(word(value));
  1192. end else if (value >= -2147483648) and (value <= 2147483647) then begin
  1193. Output.WriteByte(Ord(vaInt32));
  1194. WriteDWord(longword(value));
  1195. end else begin
  1196. Output.WriteByte(ord(vaInt64));
  1197. WriteQWord(qword(value));
  1198. end;
  1199. end;
  1200. procedure ProcessWideString(const left : widestring);
  1201. var ws : widestring;
  1202. begin
  1203. ws:=left+parser.TokenWideString;
  1204. while parser.NextToken = '+' do
  1205. begin
  1206. parser.NextToken; // Get next string fragment
  1207. if not (parser.Token in [toString,toWString]) then
  1208. parser.CheckToken(toWString);
  1209. ws:=ws+parser.TokenWideString;
  1210. end;
  1211. Output.WriteByte(Ord(vaWstring));
  1212. WriteWString(ws);
  1213. end;
  1214. procedure ProcessProperty; forward;
  1215. procedure ProcessValue;
  1216. var
  1217. {$ifndef FPUNONE}
  1218. flt: Extended;
  1219. {$endif}
  1220. s: String;
  1221. stream: TMemoryStream;
  1222. begin
  1223. case parser.Token of
  1224. toInteger:
  1225. begin
  1226. WriteInteger(parser.TokenInt);
  1227. parser.NextToken;
  1228. end;
  1229. {$ifndef FPUNONE}
  1230. toFloat:
  1231. begin
  1232. Output.WriteByte(Ord(vaExtended));
  1233. flt := Parser.TokenFloat;
  1234. WriteExtended(flt);
  1235. parser.NextToken;
  1236. end;
  1237. {$endif}
  1238. toString:
  1239. begin
  1240. s := parser.TokenString;
  1241. while parser.NextToken = '+' do
  1242. begin
  1243. parser.NextToken; // Get next string fragment
  1244. case parser.Token of
  1245. toString : s:=s+parser.TokenString;
  1246. toWString : begin
  1247. ProcessWideString(s);
  1248. exit;
  1249. end
  1250. else parser.CheckToken(toString);
  1251. end;
  1252. end;
  1253. if (length(S)>255) then
  1254. begin
  1255. Output.WriteByte(Ord(vaLString));
  1256. WriteLString(S);
  1257. end
  1258. else
  1259. begin
  1260. Output.WriteByte(Ord(vaString));
  1261. WriteString(s);
  1262. end;
  1263. end;
  1264. toWString:
  1265. ProcessWideString('');
  1266. toSymbol:
  1267. begin
  1268. if CompareText(parser.TokenString, 'True') = 0 then
  1269. Output.WriteByte(Ord(vaTrue))
  1270. else if CompareText(parser.TokenString, 'False') = 0 then
  1271. Output.WriteByte(Ord(vaFalse))
  1272. else if CompareText(parser.TokenString, 'nil') = 0 then
  1273. Output.WriteByte(Ord(vaNil))
  1274. else
  1275. begin
  1276. Output.WriteByte(Ord(vaIdent));
  1277. WriteString(parser.TokenComponentIdent);
  1278. end;
  1279. Parser.NextToken;
  1280. end;
  1281. // Set
  1282. '[':
  1283. begin
  1284. parser.NextToken;
  1285. Output.WriteByte(Ord(vaSet));
  1286. if parser.Token <> ']' then
  1287. while True do
  1288. begin
  1289. parser.CheckToken(toSymbol);
  1290. WriteString(parser.TokenString);
  1291. parser.NextToken;
  1292. if parser.Token = ']' then
  1293. break;
  1294. parser.CheckToken(',');
  1295. parser.NextToken;
  1296. end;
  1297. Output.WriteByte(0);
  1298. parser.NextToken;
  1299. end;
  1300. // List
  1301. '(':
  1302. begin
  1303. parser.NextToken;
  1304. Output.WriteByte(Ord(vaList));
  1305. while parser.Token <> ')' do
  1306. ProcessValue;
  1307. Output.WriteByte(0);
  1308. parser.NextToken;
  1309. end;
  1310. // Collection
  1311. '<':
  1312. begin
  1313. parser.NextToken;
  1314. Output.WriteByte(Ord(vaCollection));
  1315. while parser.Token <> '>' do
  1316. begin
  1317. parser.CheckTokenSymbol('item');
  1318. parser.NextToken;
  1319. // ConvertOrder
  1320. Output.WriteByte(Ord(vaList));
  1321. while not parser.TokenSymbolIs('end') do
  1322. ProcessProperty;
  1323. parser.NextToken; // Skip 'end'
  1324. Output.WriteByte(0);
  1325. end;
  1326. Output.WriteByte(0);
  1327. parser.NextToken;
  1328. end;
  1329. // Binary data
  1330. '{':
  1331. begin
  1332. Output.WriteByte(Ord(vaBinary));
  1333. stream := TMemoryStream.Create;
  1334. try
  1335. parser.HexToBinary(stream);
  1336. WriteDWord(stream.Size);
  1337. Output.WriteBuffer(Stream.Memory^, stream.Size);
  1338. finally
  1339. stream.Free;
  1340. end;
  1341. parser.NextToken;
  1342. end;
  1343. else
  1344. parser.Error(SInvalidProperty);
  1345. end;
  1346. end;
  1347. procedure ProcessProperty;
  1348. var
  1349. name: String;
  1350. begin
  1351. // Get name of property
  1352. parser.CheckToken(toSymbol);
  1353. name := parser.TokenString;
  1354. while True do begin
  1355. parser.NextToken;
  1356. if parser.Token <> '.' then break;
  1357. parser.NextToken;
  1358. parser.CheckToken(toSymbol);
  1359. name := name + '.' + parser.TokenString;
  1360. end;
  1361. WriteString(name);
  1362. parser.CheckToken('=');
  1363. parser.NextToken;
  1364. ProcessValue;
  1365. end;
  1366. procedure ProcessObject;
  1367. var
  1368. Flags: Byte;
  1369. ObjectName, ObjectType: String;
  1370. ChildPos: Integer;
  1371. begin
  1372. if parser.TokenSymbolIs('OBJECT') then
  1373. Flags :=0 { IsInherited := False }
  1374. else begin
  1375. if parser.TokenSymbolIs('INHERITED') then
  1376. Flags := 1 { IsInherited := True; }
  1377. else begin
  1378. parser.CheckTokenSymbol('INLINE');
  1379. Flags := 4;
  1380. end;
  1381. end;
  1382. parser.NextToken;
  1383. parser.CheckToken(toSymbol);
  1384. ObjectName := '';
  1385. ObjectType := parser.TokenString;
  1386. parser.NextToken;
  1387. if parser.Token = ':' then begin
  1388. parser.NextToken;
  1389. parser.CheckToken(toSymbol);
  1390. ObjectName := ObjectType;
  1391. ObjectType := parser.TokenString;
  1392. parser.NextToken;
  1393. if parser.Token = '[' then begin
  1394. parser.NextToken;
  1395. ChildPos := parser.TokenInt;
  1396. parser.NextToken;
  1397. parser.CheckToken(']');
  1398. parser.NextToken;
  1399. Flags := Flags or 2;
  1400. end;
  1401. end;
  1402. if Flags <> 0 then begin
  1403. Output.WriteByte($f0 or Flags);
  1404. if (Flags and 2) <> 0 then
  1405. WriteInteger(ChildPos);
  1406. end;
  1407. WriteString(ObjectType);
  1408. WriteString(ObjectName);
  1409. // Convert property list
  1410. while not (parser.TokenSymbolIs('END') or
  1411. parser.TokenSymbolIs('OBJECT') or
  1412. parser.TokenSymbolIs('INHERITED') or
  1413. parser.TokenSymbolIs('INLINE')) do
  1414. ProcessProperty;
  1415. Output.WriteByte(0); // Terminate property list
  1416. // Convert child objects
  1417. while not parser.TokenSymbolIs('END') do ProcessObject;
  1418. parser.NextToken; // Skip end token
  1419. Output.WriteByte(0); // Terminate property list
  1420. end;
  1421. const
  1422. signature: PChar = 'TPF0';
  1423. begin
  1424. parser := TParser.Create(Input);
  1425. try
  1426. Output.WriteBuffer(signature[0], 4);
  1427. ProcessObject;
  1428. finally
  1429. parser.Free;
  1430. end;
  1431. end;
  1432. procedure ObjectResourceToText(Input, Output: TStream);
  1433. begin
  1434. Input.ReadResHeader;
  1435. ObjectBinaryToText(Input, Output);
  1436. end;
  1437. procedure ObjectTextToResource(Input, Output: TStream);
  1438. var
  1439. StartPos, FixupInfo: LongInt;
  1440. parser: TParser;
  1441. name: String;
  1442. begin
  1443. // Get form type name
  1444. StartPos := Input.Position;
  1445. parser := TParser.Create(Input);
  1446. try
  1447. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  1448. parser.NextToken;
  1449. parser.CheckToken(toSymbol);
  1450. parser.NextToken;
  1451. parser.CheckToken(':');
  1452. parser.NextToken;
  1453. parser.CheckToken(toSymbol);
  1454. name := parser.TokenString;
  1455. finally
  1456. parser.Free;
  1457. Input.Position := StartPos;
  1458. end;
  1459. name := UpperCase(name);
  1460. Output.WriteResourceHeader(name,FixupInfo); // Write resource header
  1461. ObjectTextToBinary(Input, Output); // Convert the stuff!
  1462. Output.FixupResourceHeader(FixupInfo); // Insert real resource data size
  1463. end;
  1464. { Utility routines }
  1465. function LineStart(Buffer, BufPos: PChar): PChar;
  1466. begin
  1467. Result := BufPos;
  1468. while Result > Buffer do begin
  1469. Dec(Result);
  1470. if Result[0] = #10 then break;
  1471. end;
  1472. end;
  1473. procedure CommonInit;
  1474. begin
  1475. InitCriticalSection(SynchronizeCritSect);
  1476. ExecuteEvent:=RtlEventCreate;
  1477. SynchronizeTimeoutEvent:=RtlEventCreate;
  1478. DoSynchronizeMethod:=false;
  1479. MainThreadID:=GetCurrentThreadID;
  1480. InitCriticalsection(ResolveSection);
  1481. InitHandlerList:=Nil;
  1482. FindGlobalComponentList:=nil;
  1483. IntConstList := TThreadList.Create;
  1484. ClassList := TThreadList.Create;
  1485. ClassAliasList := TStringList.Create;
  1486. { on unix this maps to a simple rw synchornizer }
  1487. GlobalNameSpace := TMultiReadExclusiveWriteSynchronizer.Create;
  1488. RegisterInitComponentHandler(TComponent,@DefaultInitHandler);
  1489. end;
  1490. procedure CommonCleanup;
  1491. var
  1492. i: Integer;
  1493. begin
  1494. GlobalNameSpace.BeginWrite;
  1495. with IntConstList.LockList do
  1496. try
  1497. for i := 0 to Count - 1 do
  1498. TIntConst(Items[I]).Free;
  1499. finally
  1500. IntConstList.UnlockList;
  1501. end;
  1502. IntConstList.Free;
  1503. ClassList.Free;
  1504. ClassAliasList.Free;
  1505. RemoveFixupReferences(nil, '');
  1506. DoneCriticalsection(ResolveSection);
  1507. GlobalLists.Free;
  1508. ComponentPages.Free;
  1509. FreeAndNil(NeedResolving);
  1510. { GlobalNameSpace is an interface so this is enough }
  1511. GlobalNameSpace:=nil;
  1512. if (InitHandlerList<>Nil) then
  1513. for i := 0 to InitHandlerList.Count - 1 do
  1514. TInitHandler(InitHandlerList.Items[I]).Free;
  1515. InitHandlerList.Free;
  1516. InitHandlerList:=Nil;
  1517. FindGlobalComponentList.Free;
  1518. FindGlobalComponentList:=nil;
  1519. DoneCriticalSection(SynchronizeCritSect);
  1520. RtlEventDestroy(ExecuteEvent);
  1521. RtlEventDestroy(SynchronizeTimeoutEvent);
  1522. end;
  1523. { TFiler implementation }
  1524. {$i filer.inc}
  1525. { TReader implementation }
  1526. {$i reader.inc}
  1527. { TWriter implementations }
  1528. {$i writer.inc}
  1529. {$i twriter.inc}