classes.inc 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by Michael Van Canneyt and Florian Klaempfl
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {**********************************************************************
  12. * Class implementations are in separate files. *
  13. **********************************************************************}
  14. var
  15. ClassList : TThreadlist;
  16. ClassAliasList : TStringList;
  17. {
  18. Include all message strings
  19. Add a language with IFDEF LANG_NAME
  20. just befor the final ELSE. This way English will always be the default.
  21. }
  22. {$IFDEF LANG_GERMAN}
  23. {$i constsg.inc}
  24. {$ELSE}
  25. {$IFDEF LANG_SPANISH}
  26. {$i constss.inc}
  27. {$ELSE}
  28. {$i constse.inc}
  29. {$ENDIF}
  30. {$ENDIF}
  31. { Utility routines }
  32. {$i util.inc}
  33. { TBits implementation }
  34. {$i bits.inc}
  35. { All streams implementations: }
  36. { Tstreams THandleStream TFileStream TResourcseStreams TStringStream }
  37. { TCustomMemoryStream TMemoryStream }
  38. {$i streams.inc}
  39. { TParser implementation}
  40. {$i parser.inc}
  41. { TCollection and TCollectionItem implementations }
  42. {$i collect.inc}
  43. { TList and TThreadList implementations }
  44. {$i lists.inc}
  45. { TStrings and TStringList implementations }
  46. {$i stringl.inc}
  47. { TThread implementation }
  48. {$i thread.inc}
  49. { TPersistent implementation }
  50. {$i persist.inc }
  51. { TComponent implementation }
  52. {$i compon.inc}
  53. { TBasicAction implementation }
  54. {$i action.inc}
  55. { TDataModule implementation }
  56. {$i dm.inc}
  57. { Class and component registration routines }
  58. {$I cregist.inc}
  59. { Interface related stuff }
  60. {$ifdef HASINTF}
  61. {$I intf.inc}
  62. {$endif HASINTF}
  63. {**********************************************************************
  64. * Miscellaneous procedures and functions *
  65. **********************************************************************}
  66. { Point and rectangle constructors }
  67. function Point(AX, AY: Integer): TPoint;
  68. begin
  69. with Result do
  70. begin
  71. X := AX;
  72. Y := AY;
  73. end;
  74. end;
  75. function SmallPoint(AX, AY: SmallInt): TSmallPoint;
  76. begin
  77. with Result do
  78. begin
  79. X := AX;
  80. Y := AY;
  81. end;
  82. end;
  83. function Rect(ALeft, ATop, ARight, ABottom: Integer): TRect;
  84. begin
  85. with Result do
  86. begin
  87. Left := ALeft;
  88. Top := ATop;
  89. Right := ARight;
  90. Bottom := ABottom;
  91. end;
  92. end;
  93. function Bounds(ALeft, ATop, AWidth, AHeight: Integer): TRect;
  94. begin
  95. with Result do
  96. begin
  97. Left := ALeft;
  98. Top := ATop;
  99. Right := ALeft + AWidth;
  100. Bottom := ATop + AHeight;
  101. end;
  102. end;
  103. { Object filing routines }
  104. var
  105. IntConstList: TThreadList;
  106. type
  107. TIntConst = class
  108. IntegerType: PTypeInfo; // The integer type RTTI pointer
  109. IdentToIntFn: TIdentToInt; // Identifier to Integer conversion
  110. IntToIdentFn: TIntToIdent; // Integer to Identifier conversion
  111. constructor Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  112. AIntToIdent: TIntToIdent);
  113. end;
  114. constructor TIntConst.Create(AIntegerType: PTypeInfo; AIdentToInt: TIdentToInt;
  115. AIntToIdent: TIntToIdent);
  116. begin
  117. IntegerType := AIntegerType;
  118. IdentToIntFn := AIdentToInt;
  119. IntToIdentFn := AIntToIdent;
  120. end;
  121. procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;
  122. IntToIdentFn: TIntToIdent);
  123. begin
  124. IntConstList.Add(TIntConst.Create(IntegerType, IdentToIntFn, IntToIdentFn));
  125. end;
  126. function FindIntToIdent(AIntegerType: Pointer): TIntToIdent;
  127. var
  128. i: Integer;
  129. begin
  130. with IntConstList.LockList do
  131. try
  132. for i := 0 to Count - 1 do
  133. if TIntConst(Items[i]).IntegerType = AIntegerType then
  134. exit(TIntConst(Items[i]).IntToIdentFn);
  135. Result := nil;
  136. finally
  137. IntConstList.UnlockList;
  138. end;
  139. end;
  140. function FindIdentToInt(AIntegerType: Pointer): TIdentToInt;
  141. var
  142. i: Integer;
  143. begin
  144. with IntConstList.LockList do
  145. try
  146. for i := 0 to Count - 1 do
  147. with TIntConst(Items[I]) do
  148. if TIntConst(Items[I]).IntegerType = AIntegerType then
  149. exit(IdentToIntFn);
  150. Result := nil;
  151. finally
  152. IntConstList.UnlockList;
  153. end;
  154. end;
  155. function IdentToInt(const Ident: String; var Int: LongInt;
  156. const Map: array of TIdentMapEntry): Boolean;
  157. var
  158. i: Integer;
  159. begin
  160. for i := Low(Map) to High(Map) do
  161. if CompareText(Map[i].Name, Ident) = 0 then
  162. begin
  163. Int := Map[i].Value;
  164. exit(True);
  165. end;
  166. Result := False;
  167. end;
  168. function IntToIdent(Int: LongInt; var Ident: String;
  169. const Map: array of TIdentMapEntry): Boolean;
  170. var
  171. i: Integer;
  172. begin
  173. for i := Low(Map) to High(Map) do
  174. if Map[i].Value = Int then
  175. begin
  176. Ident := Map[i].Name;
  177. exit(True);
  178. end;
  179. Result := False;
  180. end;
  181. { TPropFixup }
  182. type
  183. TPropFixup = class
  184. FInstance: TPersistent;
  185. FInstanceRoot: TComponent;
  186. FPropInfo: PPropInfo;
  187. FRootName: string;
  188. FName: string;
  189. constructor Create(AInstance: TPersistent; AInstanceRoot: TComponent;
  190. APropInfo: PPropInfo; const ARootName, AName: String);
  191. function MakeGlobalReference: Boolean;
  192. end;
  193. var
  194. GlobalFixupList: TThreadList;
  195. constructor TPropFixup.Create(AInstance: TPersistent; AInstanceRoot: TComponent;
  196. APropInfo: PPropInfo; const ARootName, AName: String);
  197. begin
  198. FInstance := AInstance;
  199. FInstanceRoot := AInstanceRoot;
  200. FPropInfo := APropInfo;
  201. FRootName := ARootName;
  202. FName := AName;
  203. end;
  204. function TPropFixup.MakeGlobalReference: Boolean;
  205. var
  206. i: Integer;
  207. s, p: PChar;
  208. begin
  209. i := Pos('.', FName);
  210. if i = 0 then
  211. exit(False);
  212. FRootName := Copy(FName, 1, i - 1);
  213. FName := Copy(FName, i + 1, Length(FName));
  214. Result := True;
  215. end;
  216. Type
  217. TInitHandler = Class(TObject)
  218. AHandler : TInitComponentHandler;
  219. AClass : TComponentClass;
  220. end;
  221. Var
  222. InitHandlerList : TList;
  223. procedure RegisterInitComponentHandler(ComponentClass: TComponentClass; Handler: TInitComponentHandler);
  224. Var
  225. I : Integer;
  226. H: TInitHandler;
  227. begin
  228. If (InitHandlerList=Nil) then
  229. InitHandlerList:=TList.Create;
  230. H:=TInitHandler.Create;
  231. H.Aclass:=ComponentClass;
  232. H.AHandler:=Handler;
  233. With InitHandlerList do
  234. begin
  235. I:=0;
  236. While (I<Count) and not H.AClass.InheritsFrom(TInitHandler(Items[i]).AClass) do
  237. Inc(I);
  238. InitHandlerList.Insert(I,H);
  239. end;
  240. end;
  241. function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
  242. Var
  243. I : Integer;
  244. begin
  245. I:=0;
  246. Result:=False;
  247. With InitHandlerList do
  248. begin
  249. I:=0;
  250. // Instance is the normally the lowest one, so that one should be used when searching.
  251. While Not result and (I<Count) do
  252. begin
  253. If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
  254. Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
  255. Inc(I);
  256. end;
  257. end;
  258. end;
  259. function InitComponentRes(const ResName: String; Instance: TComponent): Boolean;
  260. begin
  261. { !!!: Too Win32-specific }
  262. InitComponentRes := False;
  263. end;
  264. function ReadComponentRes(const ResName: String; Instance: TComponent): TComponent;
  265. begin
  266. { !!!: Too Win32-specific }
  267. ReadComponentRes := nil;
  268. end;
  269. function ReadComponentResEx(HInstance: THandle; const ResName: String): TComponent;
  270. begin
  271. { !!!: Too Win32-specific in VCL }
  272. ReadComponentResEx := nil;
  273. end;
  274. function ReadComponentResFile(const FileName: String; Instance: TComponent): TComponent;
  275. var
  276. FileStream: TStream;
  277. begin
  278. FileStream := TFileStream.Create(FileName, fmOpenRead {!!!:or fmShareDenyWrite});
  279. try
  280. Result := FileStream.ReadComponentRes(Instance);
  281. finally
  282. FileStream.Free;
  283. end;
  284. end;
  285. procedure WriteComponentResFile(const FileName: String; Instance: TComponent);
  286. var
  287. FileStream: TStream;
  288. begin
  289. FileStream := TFileStream.Create(FileName, fmCreate);
  290. try
  291. FileStream.WriteComponentRes(Instance.ClassName, Instance);
  292. finally
  293. FileStream.Free;
  294. end;
  295. end;
  296. procedure GlobalFixupReferences;
  297. var
  298. GlobalList, DoneList, ToDoList: TList;
  299. I, Index: Integer;
  300. Root: TComponent;
  301. Instance: TPersistent;
  302. Reference: Pointer;
  303. begin
  304. if not Assigned(FindGlobalComponent) then
  305. exit;
  306. {!!!: GlobalNameSpace.BeginWrite;
  307. try}
  308. GlobalList := GlobalFixupList.LockList;
  309. try
  310. if GlobalList.Count > 0 then
  311. begin
  312. ToDoList := nil;
  313. DoneList := TList.Create;
  314. ToDoList := TList.Create;
  315. try
  316. i := 0;
  317. while i < GlobalList.Count do
  318. with TPropFixup(GlobalList[i]) do
  319. begin
  320. Root := FindGlobalComponent(FRootName);
  321. if Assigned(Root) or (GetOrdProp(FInstance, FPropInfo) <> 0) then
  322. begin
  323. if Assigned(Root) then
  324. begin
  325. Reference := FindNestedComponent(Root, FName);
  326. SetOrdProp(FInstance, FPropInfo, Longint(Reference));
  327. end;
  328. // Move component to list of done components, if necessary
  329. if (DoneList.IndexOf(FInstance) < 0) and
  330. (ToDoList.IndexOf(FInstance) >= 0) then
  331. DoneList.Add(FInstance);
  332. GlobalList.Delete(i);
  333. Free; // ...the fixup
  334. end else
  335. begin
  336. // Move component to list of components to process, if necessary
  337. Index := DoneList.IndexOf(FInstance);
  338. if Index <> -1 then
  339. DoneList.Delete(Index);
  340. if ToDoList.IndexOf(FInstance) < 0 then
  341. ToDoList.Add(FInstance);
  342. Inc(i);
  343. end;
  344. end;
  345. for i := 0 to DoneList.Count - 1 do
  346. begin
  347. Instance := TPersistent(DoneList[I]);
  348. if Instance.InheritsFrom(TComponent) then
  349. Exclude(TComponent(Instance).FComponentState, csFixups);
  350. end;
  351. finally
  352. ToDoList.Free;
  353. DoneList.Free;
  354. end;
  355. end;
  356. finally
  357. GlobalFixupList.UnlockList;
  358. end;
  359. {finally
  360. GlobalNameSpace.EndWrite;
  361. end;}
  362. end;
  363. function IsStringInList(const AString: String; AList: TStrings): Boolean;
  364. var
  365. i: Integer;
  366. begin
  367. for i := 0 to AList.Count - 1 do
  368. if CompareText(AList[i], AString) = 0 then
  369. exit(True);
  370. Result := False;
  371. end;
  372. procedure GetFixupReferenceNames(Root: TComponent; Names: TStrings);
  373. var
  374. i: Integer;
  375. CurFixup: TPropFixup;
  376. begin
  377. with GlobalFixupList.LockList do
  378. try
  379. for i := 0 to Count - 1 do
  380. begin
  381. CurFixup := TPropFixup(Items[i]);
  382. if ((not Assigned(Root)) or (CurFixup.FInstanceRoot = Root)) and
  383. not IsStringInList(CurFixup.FRootName, Names) then
  384. Names.Add(CurFixup.FRootName);
  385. end;
  386. finally
  387. GlobalFixupList.UnlockList;
  388. end;
  389. end;
  390. procedure GetFixupInstanceNames(Root: TComponent;
  391. const ReferenceRootName: string; Names: TStrings);
  392. var
  393. i: Integer;
  394. CurFixup: TPropFixup;
  395. begin
  396. with GlobalFixupList.LockList do
  397. try
  398. for i := 0 to Count - 1 do
  399. begin
  400. CurFixup := TPropFixup(Items[i]);
  401. if (CurFixup.FInstanceRoot = Root) and
  402. (UpperCase(ReferenceRootName) = UpperCase(CurFixup.FRootName)) and
  403. not IsStringInList(CurFixup.FName, Names) then
  404. Names.Add(CurFixup.FName);
  405. end;
  406. finally
  407. GlobalFixupList.UnlockList;
  408. end;
  409. end;
  410. procedure RedirectFixupReferences(Root: TComponent; const OldRootName,
  411. NewRootName: string);
  412. var
  413. i: Integer;
  414. CurFixup: TPropFixup;
  415. begin
  416. with GlobalFixupList.LockList do
  417. try
  418. for i := 0 to Count - 1 do
  419. begin
  420. CurFixup := TPropFixup(Items[i]);
  421. if ((not Assigned(Root)) or (CurFixup.FInstanceRoot = Root)) and
  422. (UpperCase(OldRootName) = UpperCase(CurFixup.FRootName)) then
  423. CurFixup.FRootName := NewRootName;
  424. end;
  425. GlobalFixupReferences;
  426. finally
  427. GlobalFixupList.Unlocklist;
  428. end;
  429. end;
  430. procedure RemoveFixupReferences(Root: TComponent; const RootName: string);
  431. var
  432. i: Integer;
  433. CurFixup: TPropFixup;
  434. begin
  435. if not Assigned(GlobalFixupList) then
  436. exit;
  437. with GlobalFixupList.LockList do
  438. try
  439. for i := Count - 1 downto 0 do
  440. begin
  441. CurFixup := TPropFixup(Items[i]);
  442. if ((not Assigned(Root)) or (CurFixup.FInstanceRoot = Root)) and
  443. ((Length(RootName) = 0) or
  444. (UpperCase(RootName) = UpperCase(CurFixup.FRootName))) then
  445. begin
  446. Delete(i);
  447. CurFixup.Free;
  448. end;
  449. end;
  450. finally
  451. GlobalFixupList.UnlockList;
  452. end;
  453. end;
  454. procedure RemoveFixups(Instance: TPersistent);
  455. var
  456. i: Integer;
  457. CurFixup: TPropFixup;
  458. begin
  459. if not Assigned(GlobalFixupList) then
  460. exit;
  461. with GlobalFixupList.LockList do
  462. try
  463. for i := Count - 1 downto 0 do
  464. begin
  465. CurFixup := TPropFixup(Items[i]);
  466. if (CurFixup.FInstance = Instance) then
  467. begin
  468. Delete(i);
  469. CurFixup.Free;
  470. end;
  471. end;
  472. finally
  473. GlobalFixupList.UnlockList;
  474. end;
  475. end;
  476. function FindNestedComponent(Root: TComponent; const NamePath: string): TComponent;
  477. var
  478. Current, Found: TComponent;
  479. s, p: PChar;
  480. Name: String;
  481. begin
  482. Result := nil;
  483. if Length(NamePath) > 0 then
  484. begin
  485. Current := Root;
  486. p := PChar(NamePath);
  487. while p[0] <> #0 do
  488. begin
  489. s := p;
  490. while not (p^ in ['.', '-', #0]) do
  491. Inc(p);
  492. SetString(Name, s, p - s);
  493. Found := Current.FindComponent(Name);
  494. if (not Assigned(Found)) and (UpperCase(Name) = 'OWNER') then
  495. Found := Current;
  496. if not Assigned(Found) then exit;
  497. // Remove the dereference operator from the name
  498. if p[0] = '.' then
  499. Inc(P);
  500. if p[0] = '-' then
  501. Inc(P);
  502. if p[0] = '>' then
  503. Inc(P);
  504. Current := Found;
  505. end;
  506. end;
  507. Result := Current;
  508. end;
  509. {!!!: Should be threadvar - doesn't work for all platforms yet!}
  510. var
  511. GlobalLoaded, GlobalLists: TList;
  512. procedure BeginGlobalLoading;
  513. begin
  514. if not Assigned(GlobalLists) then
  515. GlobalLists := TList.Create;
  516. GlobalLists.Add(GlobalLoaded);
  517. GlobalLoaded := TList.Create;
  518. end;
  519. { Notify all global components that they have been loaded completely }
  520. procedure NotifyGlobalLoading;
  521. var
  522. i: Integer;
  523. begin
  524. for i := 0 to GlobalLoaded.Count - 1 do
  525. TComponent(GlobalLoaded[i]).Loaded;
  526. end;
  527. procedure EndGlobalLoading;
  528. begin
  529. { Free the memory occupied by BeginGlobalLoading }
  530. GlobalLoaded.Free;
  531. GlobalLoaded := TList(GlobalLists.Last);
  532. GlobalLists.Delete(GlobalLists.Count - 1);
  533. if GlobalLists.Count = 0 then
  534. begin
  535. GlobalLists.Free;
  536. GlobalLists := nil;
  537. end;
  538. end;
  539. function CollectionsEqual(C1, C2: TCollection): Boolean;
  540. begin
  541. // !!!: Implement this
  542. CollectionsEqual:=false;
  543. end;
  544. { Object conversion routines }
  545. procedure ObjectBinaryToText(Input, Output: TStream);
  546. procedure OutStr(s: String);
  547. begin
  548. if Length(s) > 0 then
  549. Output.Write(s[1], Length(s));
  550. end;
  551. procedure OutLn(s: String);
  552. begin
  553. OutStr(s + #10);
  554. end;
  555. procedure OutString(s: String);
  556. var
  557. res, NewStr: String;
  558. i: Integer;
  559. InString, NewInString: Boolean;
  560. begin
  561. res := '';
  562. InString := False;
  563. for i := 1 to Length(s) do begin
  564. NewInString := InString;
  565. case s[i] of
  566. #0..#31: begin
  567. if InString then
  568. NewInString := False;
  569. NewStr := '#' + IntToStr(Ord(s[i]));
  570. end;
  571. '''':
  572. if InString then NewStr := ''''''
  573. else NewStr := '''''''';
  574. else begin
  575. if not InString then
  576. NewInString := True;
  577. NewStr := s[i];
  578. end;
  579. end;
  580. if NewInString <> InString then begin
  581. NewStr := '''' + NewStr;
  582. InString := NewInString;
  583. end;
  584. res := res + NewStr;
  585. end;
  586. if InString then res := res + '''';
  587. OutStr(res);
  588. end;
  589. function ReadInt(ValueType: TValueType): LongInt;
  590. begin
  591. case ValueType of
  592. vaInt8: Result := ShortInt(Input.ReadByte);
  593. vaInt16: Result := SmallInt(Input.ReadWord);
  594. vaInt32: Result := LongInt(Input.ReadDWord);
  595. end;
  596. end;
  597. function ReadInt: LongInt;
  598. begin
  599. Result := ReadInt(TValueType(Input.ReadByte));
  600. end;
  601. function ReadSStr: String;
  602. var
  603. len: Byte;
  604. begin
  605. len := Input.ReadByte;
  606. SetLength(Result, len);
  607. Input.Read(Result[1], len);
  608. end;
  609. procedure ReadPropList(indent: String);
  610. procedure ProcessValue(ValueType: TValueType; Indent: String);
  611. procedure Stop(s: String);
  612. begin
  613. WriteLn(s);
  614. Halt;
  615. end;
  616. procedure ProcessBinary;
  617. var
  618. ToDo, DoNow, i: LongInt;
  619. lbuf: array[0..31] of Byte;
  620. s: String;
  621. begin
  622. ToDo := Input.ReadDWord;
  623. OutLn('{');
  624. while ToDo > 0 do begin
  625. DoNow := ToDo;
  626. if DoNow > 32 then DoNow := 32;
  627. Dec(ToDo, DoNow);
  628. s := Indent + ' ';
  629. Input.Read(lbuf, DoNow);
  630. for i := 0 to DoNow - 1 do
  631. s := s + IntToHex(lbuf[i], 2);
  632. OutLn(s);
  633. end;
  634. OutLn(indent + '}');
  635. end;
  636. var
  637. s: String;
  638. len: LongInt;
  639. IsFirst: Boolean;
  640. ext: Extended;
  641. begin
  642. case ValueType of
  643. vaList: begin
  644. OutStr('(');
  645. IsFirst := True;
  646. while True do begin
  647. ValueType := TValueType(Input.ReadByte);
  648. if ValueType = vaNull then break;
  649. if IsFirst then begin
  650. OutLn('');
  651. IsFirst := False;
  652. end;
  653. OutStr(Indent + ' ');
  654. ProcessValue(ValueType, Indent + ' ');
  655. end;
  656. OutLn(Indent + ')');
  657. end;
  658. vaInt8: OutLn(IntToStr(ShortInt(Input.ReadByte)));
  659. vaInt16: OutLn( IntToStr(SmallInt(Input.ReadWord)));
  660. vaInt32: OutLn(IntToStr(LongInt(Input.ReadDWord)));
  661. vaExtended: begin
  662. Input.Read(ext, SizeOf(ext));
  663. OutLn(FloatToStr(ext));
  664. end;
  665. vaString: begin
  666. OutString(ReadSStr);
  667. OutLn('');
  668. end;
  669. vaIdent: OutLn(ReadSStr);
  670. vaFalse: OutLn('False');
  671. vaTrue: OutLn('True');
  672. vaBinary: ProcessBinary;
  673. vaSet: begin
  674. OutStr('[');
  675. IsFirst := True;
  676. while True do begin
  677. s := ReadSStr;
  678. if Length(s) = 0 then break;
  679. if not IsFirst then OutStr(', ');
  680. IsFirst := False;
  681. OutStr(s);
  682. end;
  683. OutLn(']');
  684. end;
  685. vaLString:
  686. Stop('!!LString!!');
  687. vaNil:
  688. OutLn('nil');
  689. vaCollection: begin
  690. OutStr('<');
  691. while Input.ReadByte <> 0 do begin
  692. OutLn(Indent);
  693. Input.Seek(-1, soFromCurrent);
  694. OutStr(indent + ' item');
  695. ValueType := TValueType(Input.ReadByte);
  696. if ValueType <> vaList then
  697. OutStr('[' + IntToStr(ReadInt(ValueType)) + ']');
  698. OutLn('');
  699. ReadPropList(indent + ' ');
  700. OutStr(indent + ' end');
  701. end;
  702. OutLn('>');
  703. end;
  704. {vaSingle: begin OutLn('!!Single!!'); exit end;
  705. vaCurrency: begin OutLn('!!Currency!!'); exit end;
  706. vaDate: begin OutLn('!!Date!!'); exit end;
  707. vaWString: begin OutLn('!!WString!!'); exit end;}
  708. else
  709. Stop(IntToStr(Ord(ValueType)));
  710. end;
  711. end;
  712. begin
  713. while Input.ReadByte <> 0 do begin
  714. Input.Seek(-1, soFromCurrent);
  715. OutStr(indent + ReadSStr + ' = ');
  716. ProcessValue(TValueType(Input.ReadByte), Indent);
  717. end;
  718. end;
  719. procedure ReadObject(indent: String);
  720. var
  721. b: Byte;
  722. ObjClassName, ObjName: String;
  723. ChildPos: LongInt;
  724. begin
  725. // Check for FilerFlags
  726. b := Input.ReadByte;
  727. if (b and $f0) = $f0 then begin
  728. if (b and 2) <> 0 then ChildPos := ReadInt;
  729. end else begin
  730. b := 0;
  731. Input.Seek(-1, soFromCurrent);
  732. end;
  733. ObjClassName := ReadSStr;
  734. ObjName := ReadSStr;
  735. OutStr(Indent);
  736. if (b and 1) <> 0 then OutStr('inherited')
  737. else OutStr('object');
  738. OutStr(' ');
  739. if ObjName <> '' then
  740. OutStr(ObjName + ': ');
  741. OutStr(ObjClassName);
  742. if (b and 2) <> 0 then OutStr('[' + IntToStr(ChildPos) + ']');
  743. OutLn('');
  744. ReadPropList(indent + ' ');
  745. while Input.ReadByte <> 0 do begin
  746. Input.Seek(-1, soFromCurrent);
  747. ReadObject(indent + ' ');
  748. end;
  749. OutLn(indent + 'end');
  750. end;
  751. type
  752. PLongWord = ^LongWord;
  753. const
  754. signature: PChar = 'TPF0';
  755. begin
  756. if Input.ReadDWord <> PLongWord(Pointer(signature))^ then
  757. raise EReadError.Create('Illegal stream image' {###SInvalidImage});
  758. ReadObject('');
  759. end;
  760. procedure ObjectTextToBinary(Input, Output: TStream);
  761. var
  762. parser: TParser;
  763. procedure WriteString(s: String);
  764. begin
  765. Output.WriteByte(Length(s));
  766. if Length(s) > 0 then
  767. Output.Write(s[1], Length(s));
  768. end;
  769. procedure WriteInteger(value: LongInt);
  770. begin
  771. if (value >= -128) and (value <= 127) then begin
  772. Output.WriteByte(Ord(vaInt8));
  773. Output.WriteByte(Byte(value));
  774. end else if (value >= -32768) and (value <= 32767) then begin
  775. Output.WriteByte(Ord(vaInt16));
  776. Output.WriteWord(Word(value));
  777. end else begin
  778. Output.WriteByte(ord(vaInt32));
  779. Output.WriteDWord(LongWord(value));
  780. end;
  781. end;
  782. procedure ProcessProperty; forward;
  783. procedure ProcessValue;
  784. var
  785. flt: Extended;
  786. s: String;
  787. stream: TMemoryStream;
  788. begin
  789. case parser.Token of
  790. toInteger:
  791. begin
  792. WriteInteger(parser.TokenInt);
  793. parser.NextToken;
  794. end;
  795. toFloat:
  796. begin
  797. Output.WriteByte(Ord(vaExtended));
  798. flt := Parser.TokenFloat;
  799. Output.Write(flt, SizeOf(flt));
  800. parser.NextToken;
  801. end;
  802. toString:
  803. begin
  804. s := parser.TokenString;
  805. while parser.NextToken = '+' do
  806. begin
  807. parser.NextToken; // Get next string fragment
  808. parser.CheckToken(toString);
  809. s := s + parser.TokenString;
  810. end;
  811. Output.WriteByte(Ord(vaString));
  812. WriteString(s);
  813. end;
  814. toSymbol:
  815. begin
  816. if CompareText(parser.TokenString, 'True') = 0 then
  817. Output.WriteByte(Ord(vaTrue))
  818. else if CompareText(parser.TokenString, 'False') = 0 then
  819. Output.WriteByte(Ord(vaFalse))
  820. else if CompareText(parser.TokenString, 'nil') = 0 then
  821. Output.WriteByte(Ord(vaNil))
  822. else
  823. begin
  824. Output.WriteByte(Ord(vaIdent));
  825. WriteString(parser.TokenComponentIdent);
  826. end;
  827. Parser.NextToken;
  828. end;
  829. // Set
  830. '[':
  831. begin
  832. parser.NextToken;
  833. Output.WriteByte(Ord(vaSet));
  834. if parser.Token <> ']' then
  835. while True do
  836. begin
  837. parser.CheckToken(toSymbol);
  838. WriteString(parser.TokenString);
  839. parser.NextToken;
  840. if parser.Token = ']' then
  841. break;
  842. parser.CheckToken(',');
  843. parser.NextToken;
  844. end;
  845. Output.WriteByte(0);
  846. parser.NextToken;
  847. end;
  848. // List
  849. '(':
  850. begin
  851. parser.NextToken;
  852. Output.WriteByte(Ord(vaList));
  853. while parser.Token <> ')' do
  854. ProcessValue;
  855. Output.WriteByte(0);
  856. parser.NextToken;
  857. end;
  858. // Collection
  859. '<':
  860. begin
  861. parser.NextToken;
  862. Output.WriteByte(Ord(vaCollection));
  863. while parser.Token <> '>' do
  864. begin
  865. parser.CheckTokenSymbol('item');
  866. parser.NextToken;
  867. // ConvertOrder
  868. Output.WriteByte(Ord(vaList));
  869. while not parser.TokenSymbolIs('end') do
  870. ProcessProperty;
  871. parser.NextToken; // Skip 'end'
  872. Output.WriteByte(0);
  873. end;
  874. Output.WriteByte(0);
  875. parser.NextToken;
  876. end;
  877. // Binary data
  878. '{':
  879. begin
  880. Output.WriteByte(Ord(vaBinary));
  881. stream := TMemoryStream.Create;
  882. try
  883. parser.HexToBinary(stream);
  884. Output.WriteDWord(stream.Size);
  885. Output.Write(Stream.Memory^, stream.Size);
  886. finally
  887. stream.Free;
  888. end;
  889. parser.NextToken;
  890. end;
  891. else
  892. parser.Error(SInvalidProperty);
  893. end;
  894. end;
  895. procedure ProcessProperty;
  896. var
  897. name: String;
  898. begin
  899. // Get name of property
  900. parser.CheckToken(toSymbol);
  901. name := parser.TokenString;
  902. while True do begin
  903. parser.NextToken;
  904. if parser.Token <> '.' then break;
  905. parser.NextToken;
  906. parser.CheckToken(toSymbol);
  907. name := name + '.' + parser.TokenString;
  908. end;
  909. WriteString(name);
  910. parser.CheckToken('=');
  911. parser.NextToken;
  912. ProcessValue;
  913. end;
  914. procedure ProcessObject;
  915. var
  916. IsInherited: Boolean;
  917. ObjectName, ObjectType: String;
  918. begin
  919. if parser.TokenSymbolIs('OBJECT') then
  920. IsInherited := False
  921. else begin
  922. parser.CheckTokenSymbol('INHERITED');
  923. IsInherited := True;
  924. end;
  925. parser.NextToken;
  926. parser.CheckToken(toSymbol);
  927. ObjectName := '';
  928. ObjectType := parser.TokenString;
  929. parser.NextToken;
  930. if parser.Token = ':' then begin
  931. parser.NextToken;
  932. parser.CheckToken(toSymbol);
  933. ObjectName := ObjectType;
  934. ObjectType := parser.TokenString;
  935. parser.NextToken;
  936. end;
  937. WriteString(ObjectType);
  938. WriteString(ObjectName);
  939. // Convert property list
  940. while not (parser.TokenSymbolIs('END') or
  941. parser.TokenSymbolIs('OBJECT') or
  942. parser.TokenSymbolIs('INHERITED')) do
  943. ProcessProperty;
  944. Output.WriteByte(0); // Terminate property list
  945. // Convert child objects
  946. while not parser.TokenSymbolIs('END') do ProcessObject;
  947. parser.NextToken; // Skip end token
  948. Output.WriteByte(0); // Terminate property list
  949. end;
  950. const
  951. signature: PChar = 'TPF0';
  952. begin
  953. parser := TParser.Create(Input);
  954. try
  955. Output.Write(signature[0], 4);
  956. ProcessObject;
  957. finally
  958. parser.Free;
  959. end;
  960. end;
  961. procedure ObjectResourceToText(Input, Output: TStream);
  962. begin
  963. Input.ReadResHeader;
  964. ObjectBinaryToText(Input, Output);
  965. end;
  966. procedure ObjectTextToResource(Input, Output: TStream);
  967. var
  968. StartPos, SizeStartPos, BinSize: LongInt;
  969. parser: TParser;
  970. name: String;
  971. begin
  972. // Get form type name
  973. StartPos := Input.Position;
  974. parser := TParser.Create(Input);
  975. try
  976. if not parser.TokenSymbolIs('OBJECT') then parser.CheckTokenSymbol('INHERITED');
  977. parser.NextToken;
  978. parser.CheckToken(toSymbol);
  979. parser.NextToken;
  980. parser.CheckToken(':');
  981. parser.NextToken;
  982. parser.CheckToken(toSymbol);
  983. name := parser.TokenString;
  984. finally
  985. parser.Free;
  986. Input.Position := StartPos;
  987. end;
  988. // Write resource header
  989. name := UpperCase(name);
  990. Output.WriteByte($ff);
  991. Output.WriteByte(10);
  992. Output.WriteByte(0);
  993. Output.Write(name[1], Length(name) + 1); // Write null-terminated form type name
  994. Output.WriteWord($1030);
  995. SizeStartPos := Output.Position;
  996. Output.WriteDWord(0); // Placeholder for data size
  997. ObjectTextToBinary(Input, Output); // Convert the stuff!
  998. BinSize := Output.Position - SizeStartPos - 4;
  999. Output.Position := SizeStartPos;
  1000. Output.WriteDWord(BinSize); // Insert real resource data size
  1001. end;
  1002. { Utility routines }
  1003. function LineStart(Buffer, BufPos: PChar): PChar;
  1004. begin
  1005. Result := BufPos;
  1006. while Result > Buffer do begin
  1007. Dec(Result);
  1008. if Result[0] = #10 then break;
  1009. end;
  1010. end;
  1011. procedure CommonInit;
  1012. begin
  1013. InitHandlerList:=Nil;
  1014. IntConstList := TThreadList.Create;
  1015. GlobalFixupList := TThreadList.Create;
  1016. ClassList := TThreadList.Create;
  1017. ClassAliasList := TStringList.Create;
  1018. end;
  1019. procedure CommonCleanup;
  1020. var
  1021. i: Integer;
  1022. begin
  1023. // !!!: GlobalNameSpace.BeginWrite;
  1024. with IntConstList.LockList do
  1025. try
  1026. for i := 0 to Count - 1 do
  1027. TIntConst(Items[I]).Free;
  1028. finally
  1029. IntConstList.UnlockList;
  1030. end;
  1031. IntConstList.Free;
  1032. ClassList.Free;
  1033. ClassAliasList.Free;
  1034. RemoveFixupReferences(nil, '');
  1035. GlobalFixupList.Free;
  1036. GlobalFixupList := nil;
  1037. GlobalLists.Free;
  1038. ComponentPages.Free;
  1039. {!!!: GlobalNameSpace.Free;
  1040. GlobalNameSpace := nil;}
  1041. InitHandlerList.Free;
  1042. InitHandlerList:=Nil;
  1043. end;
  1044. { TFiler implementation }
  1045. {$i filer.inc}
  1046. { TReader implementation }
  1047. {$i reader.inc}
  1048. { TWriter implementations }
  1049. {$i writer.inc}
  1050. {$i twriter.inc}
  1051. {
  1052. $Log$
  1053. Revision 1.14 2003-06-04 17:40:44 michael
  1054. + Minor fix by Mattias Gaertner
  1055. Revision 1.13 2003/06/04 15:27:24 michael
  1056. + TDataModule en InitInheritedComponent erbij voor Delphi 6 compatibility
  1057. Revision 1.12 2003/04/19 14:29:25 michael
  1058. + Fix from Mattias Gaertner, closes memory leak
  1059. Revision 1.11 2002/12/02 12:04:07 sg
  1060. * Fixed handling of zero-length strings (classes.inc: When converting
  1061. empty strings from text forms to binary forms; reader.inc: When reading
  1062. an empty string from a binary serialization)
  1063. Revision 1.10 2002/09/07 15:15:24 peter
  1064. * old logs removed and tabs fixed
  1065. Revision 1.9 2002/07/16 13:32:51 florian
  1066. + skeleton for TInterfaceList added
  1067. Revision 1.8 2002/01/06 21:54:49 peter
  1068. * action classes added
  1069. }