classes.inc 29 KB

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