streams.inc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  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. {* TStream *}
  13. {****************************************************************************}
  14. {$ifdef seek64bit}
  15. function TStream.GetPosition: Int64;
  16. begin
  17. Result:=Seek(0,soCurrent);
  18. end;
  19. procedure TStream.SetPosition(Pos: Int64);
  20. begin
  21. Seek(pos,soBeginning);
  22. end;
  23. procedure TStream.SetSize64(NewSize: Int64);
  24. begin
  25. // Required because can't use overloaded functions in properties
  26. SetSize(NewSize);
  27. end;
  28. function TStream.GetSize: Int64;
  29. var
  30. p : int64;
  31. begin
  32. p:=Seek(0,soCurrent);
  33. GetSize:=Seek(0,soEnd);
  34. Seek(p,soBeginning);
  35. end;
  36. procedure TStream.SetSize(NewSize: Longint);
  37. begin
  38. // We do nothing. Pipe streams don't support this
  39. // As wel as possible read-ony streams !!
  40. end;
  41. procedure TStream.SetSize(NewSize: Int64);
  42. begin
  43. // Backwards compatibility that calls the longint SetSize
  44. if (NewSize<Low(longint)) or
  45. (NewSize>High(longint)) then
  46. raise ERangeError.Create(SRangeError);
  47. SetSize(longint(NewSize));
  48. end;
  49. function TStream.Seek(Offset: Longint; Origin: Word): Longint;
  50. type
  51. TSeek64 = function(offset:Int64;Origin:TSeekorigin):Int64 of object;
  52. var
  53. CurrSeek,
  54. TStreamSeek : TSeek64;
  55. CurrClass : TClass;
  56. begin
  57. // Redirect calls to 64bit Seek, but we can't call the 64bit Seek
  58. // from TStream, because then we end up in an infinite loop
  59. CurrSeek:=nil;
  60. CurrClass:=Classtype;
  61. while (CurrClass<>nil) and
  62. (CurrClass<>TStream) do
  63. CurrClass:=CurrClass.Classparent;
  64. if CurrClass<>nil then
  65. begin
  66. CurrSeek:[email protected];
  67. TStreamSeek:=@TStream(@CurrClass).Seek;
  68. if TMethod(TStreamSeek).Code=TMethod(CurrSeek).Code then
  69. CurrSeek:=nil;
  70. end;
  71. if CurrSeek<>nil then
  72. Result:=Seek(Int64(offset),TSeekOrigin(origin))
  73. else
  74. raise EStreamError.CreateFmt(SSeekNotImplemented,[ClassName]);
  75. end;
  76. function TStream.Seek(Offset: Int64; Origin: TSeekorigin): Int64;
  77. begin
  78. // Backwards compatibility that calls the longint Seek
  79. if (Offset<Low(longint)) or
  80. (Offset>High(longint)) then
  81. raise ERangeError.Create(SRangeError);
  82. Result:=Seek(longint(Offset),ord(Origin));
  83. end;
  84. {$else seek64bit}
  85. function TStream.GetPosition: Longint;
  86. begin
  87. Result:=Seek(0,soFromCurrent);
  88. end;
  89. procedure TStream.SetPosition(Pos: Longint);
  90. begin
  91. Seek(pos,soFromBeginning);
  92. end;
  93. function TStream.GetSize: Longint;
  94. var
  95. p : longint;
  96. begin
  97. p:=GetPosition;
  98. GetSize:=Seek(0,soFromEnd);
  99. Seek(p,soFromBeginning);
  100. end;
  101. procedure TStream.SetSize(NewSize: Longint);
  102. begin
  103. // We do nothing. Pipe streams don't support this
  104. // As wel as possible read-ony streams !!
  105. end;
  106. {$endif seek64bit}
  107. procedure TStream.ReadBuffer(var Buffer; Count: Longint);
  108. begin
  109. if Read(Buffer,Count)<Count then
  110. Raise EReadError.Create(SReadError);
  111. end;
  112. procedure TStream.WriteBuffer(const Buffer; Count: Longint);
  113. begin
  114. if Write(Buffer,Count)<Count then
  115. Raise EWriteError.Create(SWriteError);
  116. end;
  117. function TStream.CopyFrom(Source: TStream; Count: Int64): Int64;
  118. var
  119. i : Int64;
  120. buffer : array[0..1023] of byte;
  121. begin
  122. CopyFrom:=0;
  123. If (Count=0) then
  124. begin
  125. // This WILL fail for non-seekable streams...
  126. Source.Position:=0;
  127. Count:=Source.Size;
  128. end;
  129. while Count>0 do
  130. begin
  131. if (Count>sizeof(buffer)) then
  132. i:=sizeof(Buffer)
  133. else
  134. i:=Count;
  135. i:=Source.Read(buffer,i);
  136. i:=Write(buffer,i);
  137. if i=0 then break;
  138. dec(count,i);
  139. CopyFrom:=CopyFrom+i;
  140. end;
  141. end;
  142. function TStream.ReadComponent(Instance: TComponent): TComponent;
  143. var
  144. Reader: TReader;
  145. begin
  146. Reader := TReader.Create(Self, 4096);
  147. try
  148. Result := Reader.ReadRootComponent(Instance);
  149. finally
  150. Reader.Free;
  151. end;
  152. end;
  153. function TStream.ReadComponentRes(Instance: TComponent): TComponent;
  154. begin
  155. ReadResHeader;
  156. Result := ReadComponent(Instance);
  157. end;
  158. procedure TStream.WriteComponent(Instance: TComponent);
  159. begin
  160. WriteDescendent(Instance, nil);
  161. end;
  162. procedure TStream.WriteComponentRes(const ResName: string; Instance: TComponent);
  163. begin
  164. WriteDescendentRes(ResName, Instance, nil);
  165. end;
  166. procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);
  167. var
  168. Driver : TAbstractObjectWriter;
  169. Writer : TWriter;
  170. begin
  171. Driver := TBinaryObjectWriter.Create(Self, 4096);
  172. Try
  173. Writer := TWriter.Create(Driver);
  174. Try
  175. Writer.WriteDescendent(Instance, Ancestor);
  176. Finally
  177. Writer.Destroy;
  178. end;
  179. Finally
  180. Driver.Free;
  181. end;
  182. end;
  183. procedure TStream.WriteDescendentRes(const ResName: string; Instance, Ancestor: TComponent);
  184. var
  185. FixupInfo: Integer;
  186. begin
  187. { Write a resource header }
  188. WriteResourceHeader(ResName, FixupInfo);
  189. { Write the instance itself }
  190. WriteDescendent(Instance, Ancestor);
  191. { Insert the correct resource size into the resource header }
  192. FixupResourceHeader(FixupInfo);
  193. end;
  194. procedure TStream.WriteResourceHeader(const ResName: string; {!!!: out} var FixupInfo: Integer);
  195. begin
  196. { Numeric resource type }
  197. WriteByte($ff);
  198. { Application defined data }
  199. WriteWord($0a);
  200. { write the name as asciiz }
  201. WriteBuffer(ResName[1],length(ResName));
  202. WriteByte(0);
  203. { Movable, Pure and Discardable }
  204. WriteWord($1030);
  205. { Placeholder for the resource size }
  206. WriteDWord(0);
  207. { Return current stream position so that the resource size can be
  208. inserted later }
  209. FixupInfo := Position;
  210. end;
  211. procedure TStream.FixupResourceHeader(FixupInfo: Integer);
  212. var
  213. ResSize : Integer;
  214. begin
  215. ResSize := Position - FixupInfo;
  216. { Insert the correct resource size into the placeholder written by
  217. WriteResourceHeader }
  218. Position := FixupInfo - 4;
  219. WriteDWord(ResSize);
  220. { Seek back to the end of the resource }
  221. Position := FixupInfo + ResSize;
  222. end;
  223. procedure TStream.ReadResHeader;
  224. begin
  225. try
  226. { application specific resource ? }
  227. if ReadByte<>$ff then
  228. raise EInvalidImage.Create(SInvalidImage);
  229. if ReadWord<>$000a then
  230. raise EInvalidImage.Create(SInvalidImage);
  231. { read name }
  232. while ReadByte<>0 do
  233. ;
  234. { check the access specifier }
  235. if ReadWord<>$1030 then
  236. raise EInvalidImage.Create(SInvalidImage);
  237. { ignore the size }
  238. ReadDWord;
  239. except
  240. on EInvalidImage do
  241. raise;
  242. else
  243. raise EInvalidImage.create(SInvalidImage);
  244. end;
  245. end;
  246. function TStream.ReadByte : Byte;
  247. var
  248. b : Byte;
  249. begin
  250. ReadBuffer(b,1);
  251. ReadByte:=b;
  252. end;
  253. function TStream.ReadWord : Word;
  254. var
  255. w : Word;
  256. begin
  257. ReadBuffer(w,2);
  258. ReadWord:=w;
  259. end;
  260. function TStream.ReadDWord : Cardinal;
  261. var
  262. d : Cardinal;
  263. begin
  264. ReadBuffer(d,4);
  265. ReadDWord:=d;
  266. end;
  267. Function TStream.ReadAnsiString : String;
  268. Type
  269. PByte = ^Byte;
  270. Var
  271. TheSize : Longint;
  272. P : PByte ;
  273. begin
  274. ReadBuffer (TheSize,SizeOf(TheSize));
  275. SetLength(Result,TheSize);
  276. // Illegal typecast if no AnsiStrings defined.
  277. if TheSize>0 then
  278. begin
  279. ReadBuffer (Pointer(Result)^,TheSize);
  280. P:=Pointer(Result)+TheSize;
  281. p^:=0;
  282. end;
  283. end;
  284. Procedure TStream.WriteAnsiString (S : String);
  285. Var L : Longint;
  286. begin
  287. L:=Length(S);
  288. WriteBuffer (L,SizeOf(L));
  289. WriteBuffer (Pointer(S)^,L);
  290. end;
  291. procedure TStream.WriteByte(b : Byte);
  292. begin
  293. WriteBuffer(b,1);
  294. end;
  295. procedure TStream.WriteWord(w : Word);
  296. begin
  297. WriteBuffer(w,2);
  298. end;
  299. procedure TStream.WriteDWord(d : Cardinal);
  300. begin
  301. WriteBuffer(d,4);
  302. end;
  303. {****************************************************************************}
  304. {* THandleStream *}
  305. {****************************************************************************}
  306. Constructor THandleStream.Create(AHandle: Integer);
  307. begin
  308. FHandle:=AHandle;
  309. end;
  310. function THandleStream.Read(var Buffer; Count: Longint): Longint;
  311. begin
  312. Result:=FileRead(FHandle,Buffer,Count);
  313. If Result=-1 then Result:=0;
  314. end;
  315. function THandleStream.Write(const Buffer; Count: Longint): Longint;
  316. begin
  317. Result:=FileWrite (FHandle,Buffer,Count);
  318. If Result=-1 then Result:=0;
  319. end;
  320. {$ifdef seek64bit}
  321. Procedure THandleStream.SetSize(NewSize: Longint);
  322. begin
  323. SetSize(Int64(NewSize));
  324. end;
  325. Procedure THandleStream.SetSize(NewSize: Int64);
  326. begin
  327. FileTruncate(FHandle,NewSize);
  328. end;
  329. function THandleStream.Seek(Offset: Int64; Origin: TSeekOrigin): Int64;
  330. begin
  331. Result:=FileSeek(FHandle,Offset,ord(Origin));
  332. end;
  333. {$else seek64bit}
  334. Procedure THandleStream.SetSize(NewSize: Longint);
  335. begin
  336. FileTruncate(FHandle,NewSize);
  337. end;
  338. function THandleStream.Seek(Offset: Longint; Origin: Word): Longint;
  339. begin
  340. Result:=FileSeek(FHandle,Offset,Origin);
  341. end;
  342. {$endif seek64bit}
  343. {****************************************************************************}
  344. {* TFileStream *}
  345. {****************************************************************************}
  346. constructor TFileStream.Create(const AFileName: string; Mode: Word);
  347. begin
  348. FFileName:=AFileName;
  349. If Mode=fmcreate then
  350. FHandle:=FileCreate(AFileName)
  351. else
  352. FHAndle:=FileOpen(AFileName,Mode);
  353. If FHandle<0 then
  354. If Mode=fmcreate then
  355. raise EFCreateError.createfmt(SFCreateError,[AFileName])
  356. else
  357. raise EFOpenError.Createfmt(SFOpenError,[AFilename]);
  358. end;
  359. constructor TFileStream.Create(const AFileName: string; Mode: Word; Rights: Cardinal);
  360. begin
  361. FFileName:=AFileName;
  362. If Mode=fmcreate then
  363. FHandle:=FileCreate(AFileName)
  364. else
  365. FHAndle:=FileOpen(AFileName,Mode);
  366. If FHandle<0 then
  367. If Mode=fmcreate then
  368. raise EFCreateError.createfmt(SFCreateError,[AFileName])
  369. else
  370. raise EFOpenError.Createfmt(SFOpenError,[AFilename]);
  371. end;
  372. destructor TFileStream.Destroy;
  373. begin
  374. FileClose(FHandle);
  375. end;
  376. {****************************************************************************}
  377. {* TCustomMemoryStream *}
  378. {****************************************************************************}
  379. procedure TCustomMemoryStream.SetPointer(Ptr: Pointer; ASize: Longint);
  380. begin
  381. FMemory:=Ptr;
  382. FSize:=ASize;
  383. end;
  384. function TCustomMemoryStream.Read(var Buffer; Count: Longint): Longint;
  385. begin
  386. Result:=0;
  387. If (FSize>0) and (FPosition<Fsize) then
  388. begin
  389. Result:=FSize-FPosition;
  390. If Result>Count then Result:=Count;
  391. Move ((FMemory+FPosition)^,Buffer,Result);
  392. FPosition:=Fposition+Result;
  393. end;
  394. end;
  395. function TCustomMemoryStream.Seek(Offset: Longint; Origin: Word): Longint;
  396. begin
  397. Case Origin of
  398. soFromBeginning : FPosition:=Offset;
  399. soFromEnd : FPosition:=FSize+Offset;
  400. soFromCurrent : FpoSition:=FPosition+Offset;
  401. end;
  402. Result:=FPosition;
  403. end;
  404. procedure TCustomMemoryStream.SaveToStream(Stream: TStream);
  405. begin
  406. if FSize>0 then Stream.WriteBuffer (FMemory^,FSize);
  407. end;
  408. procedure TCustomMemoryStream.SaveToFile(const FileName: string);
  409. Var S : TFileStream;
  410. begin
  411. S:=TFileStream.Create (FileName,fmCreate);
  412. Try
  413. SaveToStream(S);
  414. finally
  415. S.free;
  416. end;
  417. end;
  418. {****************************************************************************}
  419. {* TMemoryStream *}
  420. {****************************************************************************}
  421. Const TMSGrow = 4096; { Use 4k blocks. }
  422. procedure TMemoryStream.SetCapacity(NewCapacity: Longint);
  423. begin
  424. SetPointer (Realloc(NewCapacity),Fsize);
  425. FCapacity:=NewCapacity;
  426. end;
  427. function TMemoryStream.Realloc(var NewCapacity: Longint): Pointer;
  428. Var MoveSize : Longint;
  429. begin
  430. If NewCapacity>0 Then // round off to block size.
  431. NewCapacity := (NewCapacity + (TMSGrow-1)) and not (TMSGROW-1);
  432. // Only now check !
  433. If NewCapacity=FCapacity then
  434. Result:=FMemory
  435. else
  436. If NewCapacity=0 then
  437. FreeMem (FMemory,Fcapacity)
  438. else
  439. begin
  440. GetMem (Result,NewCapacity);
  441. If Result=Nil then
  442. Raise EStreamError.Create(SMemoryStreamError);
  443. If FCapacity>0 then
  444. begin
  445. MoveSize:=FSize;
  446. If MoveSize>NewCapacity then MoveSize:=NewCapacity;
  447. Move (Fmemory^,Result^,MoveSize);
  448. FreeMem (FMemory,FCapacity);
  449. end;
  450. end;
  451. end;
  452. destructor TMemoryStream.Destroy;
  453. begin
  454. Clear;
  455. Inherited Destroy;
  456. end;
  457. procedure TMemoryStream.Clear;
  458. begin
  459. FSize:=0;
  460. FPosition:=0;
  461. SetCapacity (0);
  462. end;
  463. procedure TMemoryStream.LoadFromStream(Stream: TStream);
  464. begin
  465. Stream.Position:=0;
  466. SetSize(Stream.Size);
  467. If FSize>0 then Stream.ReadBuffer(FMemory^,FSize);
  468. end;
  469. procedure TMemoryStream.LoadFromFile(const FileName: string);
  470. Var S : TFileStream;
  471. begin
  472. S:=TFileStream.Create (FileName,fmOpenRead);
  473. Try
  474. LoadFromStream(S);
  475. finally
  476. S.free;
  477. end;
  478. end;
  479. procedure TMemoryStream.SetSize(NewSize: Longint);
  480. begin
  481. SetCapacity (NewSize);
  482. FSize:=NewSize;
  483. IF FPosition>FSize then
  484. FPosition:=FSize;
  485. end;
  486. function TMemoryStream.Write(const Buffer; Count: Longint): Longint;
  487. Var NewPos : Longint;
  488. begin
  489. If Count=0 then
  490. exit(0);
  491. NewPos:=FPosition+Count;
  492. If NewPos>Fsize then
  493. begin
  494. IF NewPos>FCapacity then
  495. SetCapacity (NewPos);
  496. FSize:=Newpos;
  497. end;
  498. System.Move (Buffer,(FMemory+FPosition)^,Count);
  499. FPosition:=NewPos;
  500. Result:=Count;
  501. end;
  502. {****************************************************************************}
  503. {* TStringStream *}
  504. {****************************************************************************}
  505. procedure TStringStream.SetSize(NewSize: Longint);
  506. begin
  507. Setlength(FDataString,NewSize);
  508. If FPosition>NewSize then FPosition:=NewSize;
  509. end;
  510. constructor TStringStream.Create(const AString: string);
  511. begin
  512. Inherited create;
  513. FDataString:=AString;
  514. end;
  515. function TStringStream.Read(var Buffer; Count: Longint): Longint;
  516. begin
  517. Result:=Length(FDataString)-FPosition;
  518. If Result>Count then Result:=Count;
  519. // This supposes FDataString to be of type AnsiString !
  520. Move (Pchar(FDataString)[FPosition],Buffer,Result);
  521. FPosition:=FPosition+Result;
  522. end;
  523. function TStringStream.ReadString(Count: Longint): string;
  524. Var NewLen : Longint;
  525. begin
  526. NewLen:=Length(FDataString)-FPosition;
  527. If NewLen>Count then NewLen:=Count;
  528. SetLength(Result,NewLen);
  529. Read (Pointer(Result)^,NewLen);
  530. end;
  531. function TStringStream.Seek(Offset: Longint; Origin: Word): Longint;
  532. begin
  533. Case Origin of
  534. soFromBeginning : FPosition:=Offset;
  535. soFromEnd : FPosition:=Length(FDataString)+Offset;
  536. soFromCurrent : FpoSition:=FPosition+Offset;
  537. end;
  538. If FPosition>Length(FDataString) then FPosition:=Length(FDataString);
  539. If FPosition<0 then FPosition:=0;
  540. Result:=FPosition;
  541. end;
  542. function TStringStream.Write(const Buffer; Count: Longint): Longint;
  543. begin
  544. Result:=Count;
  545. SetSize(FPosition+Count);
  546. // This supposes that FDataString is of type AnsiString)
  547. Move (Buffer,PCHar(FDataString)[Fposition],Count);
  548. FPosition:=FPosition+Count;
  549. end;
  550. procedure TStringStream.WriteString(const AString: string);
  551. begin
  552. Write (PChar(Astring)[0],Length(AString));
  553. end;
  554. {****************************************************************************}
  555. {* TResourceStream *}
  556. {****************************************************************************}
  557. procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar);
  558. begin
  559. end;
  560. constructor TResourceStream.Create(Instance: THandle; const ResName: string; ResType: PChar);
  561. begin
  562. end;
  563. constructor TResourceStream.CreateFromID(Instance: THandle; ResID: Integer; ResType: PChar);
  564. begin
  565. end;
  566. destructor TResourceStream.Destroy;
  567. begin
  568. end;
  569. function TResourceStream.Write(const Buffer; Count: Longint): Longint;
  570. begin
  571. Write:=0;
  572. end;
  573. {****************************************************************************}
  574. {* TOwnerStream *}
  575. {****************************************************************************}
  576. constructor TOwnerStream.Create(ASource: TStream);
  577. begin
  578. FSource:=ASource;
  579. end;
  580. destructor TOwnerStream.Destroy;
  581. begin
  582. If FOwner then
  583. FreeAndNil(FSource);
  584. inherited Destroy;
  585. end;
  586. {
  587. $Log$
  588. Revision 1.5 2005-01-19 09:09:50 michael
  589. * Patch from Peter to fix 64bit issue in tstream.seek()
  590. Revision 1.4 2005/01/18 22:31:44 michael
  591. + Patch from Mattias Gaertner to fix CopyFrom
  592. Revision 1.3 2005/01/09 13:15:37 michael
  593. + Added TOwnerStream
  594. Revision 1.2 2003/10/30 16:30:53 peter
  595. * merged copyfrom with 0
  596. Revision 1.3 2003/10/28 22:04:29 michael
  597. + Fixed private seeksupport stuff
  598. Revision 1.2 2003/10/26 14:52:29 michael
  599. + Fixed TStream.CopyFrom with Count=0
  600. Revision 1.13 2003/07/26 16:20:50 michael
  601. + Fixed readstring from TStringStream (
  602. Revision 1.12 2002/04/25 19:14:13 sg
  603. * Fixed TStringStream.ReadString
  604. Revision 1.11 2002/12/18 16:45:33 peter
  605. * set function result in TStream.Seek(int64) found by Mattias Gaertner
  606. Revision 1.10 2002/12/18 16:35:59 peter
  607. * fix crash in Seek()
  608. Revision 1.9 2002/12/18 15:51:52 michael
  609. + Hopefully fixed some issues with int64 seek
  610. Revision 1.8 2002/10/22 09:38:39 michael
  611. + Fixed TmemoryStream.LoadFromStream, reported by Mattias Gaertner
  612. Revision 1.7 2002/09/07 15:15:25 peter
  613. * old logs removed and tabs fixed
  614. }