streams.inc 18 KB

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