streams.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  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 FHandle<0 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)
  328. else
  329. FHAndle:=FileOpen(AFileName,Mode);
  330. If FHandle<0 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. Var MoveSize : Longint;
  397. begin
  398. // round off to block size.
  399. If NewCapacity<0 Then
  400. NewCapacity:=0
  401. else
  402. NewCapacity := (NewCapacity + (TMSGrow-1)) and not (TMSGROW-1);
  403. // Only now check !
  404. If NewCapacity=FCapacity then
  405. Result:=FMemory
  406. else
  407. begin
  408. Result:=Reallocmem(FMemory,Newcapacity);
  409. If (Result=Nil) and (Newcapacity>0) then
  410. Raise EStreamError.Create(SMemoryStreamError);
  411. end;
  412. end;
  413. destructor TMemoryStream.Destroy;
  414. begin
  415. Clear;
  416. Inherited Destroy;
  417. end;
  418. procedure TMemoryStream.Clear;
  419. begin
  420. FSize:=0;
  421. FPosition:=0;
  422. SetCapacity (0);
  423. end;
  424. procedure TMemoryStream.LoadFromStream(Stream: TStream);
  425. begin
  426. Stream.Position:=0;
  427. SetSize(Stream.Size);
  428. If FSize>0 then Stream.ReadBuffer(FMemory^,FSize);
  429. end;
  430. procedure TMemoryStream.LoadFromFile(const FileName: string);
  431. Var S : TFileStream;
  432. begin
  433. S:=TFileStream.Create (FileName,fmOpenRead);
  434. Try
  435. LoadFromStream(S);
  436. finally
  437. S.free;
  438. end;
  439. end;
  440. procedure TMemoryStream.SetSize(NewSize: Longint);
  441. begin
  442. SetCapacity (NewSize);
  443. FSize:=NewSize;
  444. IF FPosition>FSize then
  445. FPosition:=FSize;
  446. end;
  447. function TMemoryStream.Write(const Buffer; Count: Longint): Longint;
  448. Var NewPos : Longint;
  449. begin
  450. If Count=0 then
  451. exit(0);
  452. NewPos:=FPosition+Count;
  453. If NewPos>Fsize then
  454. begin
  455. IF NewPos>FCapacity then
  456. SetCapacity (NewPos);
  457. FSize:=Newpos;
  458. end;
  459. System.Move (Buffer,(FMemory+FPosition)^,Count);
  460. FPosition:=NewPos;
  461. Result:=Count;
  462. end;
  463. {****************************************************************************}
  464. {* TStringStream *}
  465. {****************************************************************************}
  466. procedure TStringStream.SetSize(NewSize: Longint);
  467. begin
  468. Setlength(FDataString,NewSize);
  469. If FPosition>NewSize then FPosition:=NewSize;
  470. end;
  471. constructor TStringStream.Create(const AString: string);
  472. begin
  473. Inherited create;
  474. FDataString:=AString;
  475. end;
  476. function TStringStream.Read(var Buffer; Count: Longint): Longint;
  477. begin
  478. Result:=Length(FDataString)-FPosition;
  479. If Result>Count then Result:=Count;
  480. // This supposes FDataString to be of type AnsiString !
  481. Move (Pchar(FDataString)[FPosition],Buffer,Result);
  482. FPosition:=FPosition+Result;
  483. end;
  484. function TStringStream.ReadString(Count: Longint): string;
  485. Var NewLen : Longint;
  486. begin
  487. NewLen:=Length(FDataString)-FPosition;
  488. If NewLen>Count then NewLen:=Count;
  489. SetLength(Result,NewLen);
  490. Read (Pointer(Result)^,NewLen);
  491. end;
  492. function TStringStream.Seek(Offset: Longint; Origin: Word): Longint;
  493. begin
  494. Case Origin of
  495. soFromBeginning : FPosition:=Offset;
  496. soFromEnd : FPosition:=Length(FDataString)+Offset;
  497. soFromCurrent : FpoSition:=FPosition+Offset;
  498. end;
  499. If FPosition>Length(FDataString) then FPosition:=Length(FDataString);
  500. If FPosition<0 then FPosition:=0;
  501. Result:=FPosition;
  502. end;
  503. function TStringStream.Write(const Buffer; Count: Longint): Longint;
  504. begin
  505. Result:=Count;
  506. SetSize(FPosition+Count);
  507. // This supposes that FDataString is of type AnsiString)
  508. Move (Buffer,PChar(FDataString)[Fposition],Count);
  509. FPosition:=FPosition+Count;
  510. end;
  511. procedure TStringStream.WriteString(const AString: string);
  512. begin
  513. Write (PChar(Astring)[0],Length(AString));
  514. end;
  515. {****************************************************************************}
  516. {* TResourceStream *}
  517. {****************************************************************************}
  518. {$ifdef UNICODE}
  519. procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PWideChar);
  520. begin
  521. Res:=FindResource(Instance, Name, ResType);
  522. if Res=0 then
  523. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  524. Handle:=LoadResource(Instance,Res);
  525. if Handle=0 then
  526. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  527. SetPointer(LockResource(Handle),SizeOfResource(Instance,Res));
  528. end;
  529. constructor TResourceStream.Create(Instance: THandle; const ResName: WideString; ResType: PWideChar);
  530. begin
  531. inherited create;
  532. Initialize(Instance,PWideChar(ResName),ResType);
  533. end;
  534. constructor TResourceStream.CreateFromID(Instance: THandle; ResID: Integer; ResType: PWideChar);
  535. begin
  536. inherited create;
  537. Initialize(Instance,PWideChar(ResID),ResType);
  538. end;
  539. {$else UNICODE}
  540. procedure TResourceStream.Initialize(Instance: THandle; Name, ResType: PChar);
  541. begin
  542. Res:=FindResource(Instance, Name, ResType);
  543. if Res=0 then
  544. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  545. Handle:=LoadResource(Instance,Res);
  546. if Handle=0 then
  547. raise EResNotFound.CreateFmt(SResNotFound,[Name]);
  548. SetPointer(LockResource(Handle),SizeOfResource(Instance,Res));
  549. end;
  550. constructor TResourceStream.Create(Instance: THandle; const ResName: string; ResType: PChar);
  551. begin
  552. inherited create;
  553. Initialize(Instance,pchar(ResName),ResType);
  554. end;
  555. constructor TResourceStream.CreateFromID(Instance: THandle; ResID: Integer; ResType: PChar);
  556. begin
  557. inherited create;
  558. Initialize(Instance,pchar(PtrInt(ResID)),ResType);
  559. end;
  560. {$endif UNICODE}
  561. destructor TResourceStream.Destroy;
  562. begin
  563. UnlockResource(Handle);
  564. FreeResource(Handle);
  565. inherited destroy;
  566. end;
  567. function TResourceStream.Write(const Buffer; Count: Longint): Longint;
  568. begin
  569. raise EStreamError.Create(SCantWriteResourceStreamError);
  570. end;
  571. {****************************************************************************}
  572. {* TOwnerStream *}
  573. {****************************************************************************}
  574. constructor TOwnerStream.Create(ASource: TStream);
  575. begin
  576. FSource:=ASource;
  577. end;
  578. destructor TOwnerStream.Destroy;
  579. begin
  580. If FOwner then
  581. FreeAndNil(FSource);
  582. inherited Destroy;
  583. end;