2
0

streams.inc 18 KB

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